静态常量成员初始化和模板(vs静态函数)-这是如何工作的? 我知道C++标准(SEC 94.2段4),一个静态或整数类型成员变量可以在类内部提供一个初始化器,但是这需要在类之外(在编译单元中)定义该成员。也就是说,你需要这样做: class A { public: static const int X = 10; }; // this is required by the standard const int A::X;
我已经看到(在其他地方我也看到过这样的说法),一些编译器可以让您在没有类外定义的情况下逃脱。这适用于OS X上的gcc 4.2.1:静态常量成员初始化和模板(vs静态函数)-这是如何工作的? 我知道C++标准(SEC 94.2段4),一个静态或整数类型成员变量可以在类内部提供一个初始化器,但是这需要在类之外(在编译单元中)定义该成员。也就是说,你需要这样做: class A { public: static const int X = 10; }; // this is required by the standard const int A::X;,c++,compilation,static-members,C++,Compilation,Static Members,我已经看到(在其他地方我也看到过这样的说法),一些编译器可以让您在没有类外定义的情况下逃脱。这适用于OS X上的gcc 4.2.1: #include <iostream> class A { public: static const int X = 10; }; int main(int argc, char** argv) { std::cout << A::X << std::endl; return 0; } 添加
#include <iostream>
class A
{
public:
static const int X = 10;
};
int main(int argc, char** argv)
{
std::cout << A::X << std::endl;
return 0;
}
添加回类定义的外部使其工作
这是一个学术问题,但我想知道为什么会这样。特别是,如果我们用一个静态函数替换静态成员变量(static const int X=10;
变成static int X()
,a::X
变成a::X()
),那么它将在没有类外定义的情况下编译。我之所以提到模板,是因为std::max
是模板化的,而其他模板化函数也会复制相同的行为。它可能与模板没有特别的关系,但我想理解为什么模板会导致它们所做的行为。我假设这一定与模板和静态成员的编译/实现方式有关
PS-我在上发布了一些最小的代码,它将在没有定义的情况下编译 如果使用了静态成员变量odr,则在链接时需要该定义。(如果编译器每次引用它时都设法替换它的实际值,那么就不会使用odr。另一方面,获取它的地址肯定会使用odr) 这是完整的规则(第9.4.2节
[class.static.data]
):
如果非易失性const static
数据成员为整型或枚举型,则其在类定义中的声明可以指定大括号或相等初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。可以使用constepr
说明符在类定义中声明文本类型的static
数据成员;如果是这样,其声明应指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。[注意:在这两种情况下,该成员可能出现在常量表达式中。-结束注意]如果程序中使用odr,则该成员仍应在命名空间范围中定义,且命名空间范围定义不应包含初始值设定项。
从第3.2节[basic.def.odr]
:
如果变量的名称显示为可能的求值表达式,则使用odr,除非它是
对象,该对象满足在常量表达式中出现的要求,并立即应用左值到右值的转换
在常量表达式中出现的要求得到了满足,因此一切都取决于它是用作左值还是右值
std::max
采用左值引用,因此没有立即的左值到右值转换
与模板的唯一交互是可能有多个等效定义,链接器将选择任何一个。在您的例子中,没有模板,因此多个定义将产生“symbol multiply defined”类型的错误
当您忘记提供定义时,这两种情况(模板类的成员和普通类的成员)都会给出相同的错误:“undefined symbol”。让我们以您的第一个示例为例:
std::cout << A::X << std::endl;
std::max
函数通过引用获取其参数,换句话说,必须知道A::X
的地址才能完成调用。A::x的地址必须是已知的,这需要一个定义。您的标题是模板。我在这里没有看到任何模板(好的,std::max
是一个模板,但这完全不相关)。我确实看到类定义后缺少分号。另外,您是指第9.4.2节吗?2.4.2不存在。哦,是的,我是说9.4.2。我编辑了打字稿,更清楚地说明了我为什么要提到模板。要做到这一点,请参阅我答案中的第二个标准摘录。如果我正确理解了引号,cout.operator这不是规则的意思。只有对象A::X
必须满足在常量表达式中出现的要求,而且总是这样(根据第一段引文中的注释)。好的,我现在明白了,我现在意识到C++11通过添加来放宽规则(从C++03开始),除非它是一个满足要求的对象。
部分。谢谢。你参考的是什么版本的标准?我看的那张一定是旧的。。你能解释一下从左值到右值的转换,或者添加一个链接到解释吗?关于编译,你说得对,但没有链接,但我没有得到“符号乘法定义”,我得到的“未定义符号”指的是A::X。@dantswain:我摘录了C++11发布前的最终草案,这是目前有效的标准。如果在头文件中放入定义,将得到“symbol multiply defined”,除非父类是模板。如果没有定义,您将得到“未定义的符号”。
std::cout << A::X << std::endl;
template< class T >
const T& max( const T& a, const T& b );