Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
静态常量成员初始化和模板(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 - Fatal编程技术网

静态常量成员初始化和模板(vs静态函数)-这是如何工作的? 我知道C++标准(SEC 94.2段4),一个静态或整数类型成员变量可以在类内部提供一个初始化器,但是这需要在类之外(在编译单元中)定义该成员。也就是说,你需要这样做: class A { public: static const int X = 10; }; // this is required by the standard const int A::X;

静态常量成员初始化和模板(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; } 添加

我已经看到(在其他地方我也看到过这样的说法),一些编译器可以让您在没有类外定义的情况下逃脱。这适用于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;
}
添加回类定义的外部使其工作

这是一个学术问题,但我想知道为什么会这样。特别是,如果我们用一个静态函数替换静态成员变量(
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 );