在类static const ODR中 [英] In class static const ODR
问题描述
我对 const
成员的 static
类内初始化有点困惑。例如,在下面的代码中:
#include< iostream>
struct Foo
{
const static int n = 42;
};
// const int Foo :: n; //无ODR
void f(const int& param)
{
std :: cout<< param<<的std :: ENDL;
}
int g(const int& param)
{
return param;
}
模板< int N>
void h()
{
std :: cout<< N<的std :: ENDL;
}
int main()
{
// f(Foo :: n); //链接器错误,都是g ++ / clang ++
std :: cout<< g(Foo :: n)<<的std :: ENDL; //只有在-O(1,2或3)标志的情况下才能在g ++中执行,为什么?
h< Foo :: n>(); // this be fine
}
我没有定义 Foo :: n
(该行被注释)。所以,我希望调用 f(Foo :: n)
在链接时失败,事实上确实如此。但是,以下行 std :: cout<< g(Foo :: n)<< std :: endl;
每当我使用优化标志(如 -O1 / 2/3 $)时,仅由gcc编译和链接(clang仍然会发出链接器错误) C $ C>。
- 为什么gcc(用gcc5.2.0和gcc 4.9.3试过)编译并链接代码时优化已打开?
- 我是否正确地说,类内静态常量成员的唯一用法是在常量表达式中,例如像
h< Foo :: n>
调用,在这种情况下,代码应该链接在一起
函数的一个定义或者每个非内联
函数的定义在该程序中使用的变量; 不需要诊断
。
不同优化级别的不一致行为是完全一致的行为。
非正式地变量是 odr-used if:
其地址被取用,或者引用被绑定到它,一个函数如果对其进行函数调用或获取其地址,则会被使用。如果一个对象或函数被使用了,它的定义必须存在于程序中的某个地方;
因此,f
和g
将会是odr-uses并需要一个定义。
相关C ++ 14对odr-使用将来自 [basic.def.odr] 部分:
$ b
变量x,其名称显示为可能被评估的表达式ex是 odr-由ex使用,除非应用
左值到右值转换(4.1)给x产生一个常量表达式(5.19),它不会调用任何非平凡
函数,如果x是一个对象,则ex是一个表达式e,
潜在结果集合中的一个元素,其中左值到右值转换(4.1)应用于e ,或者e是一个丢弃的表达式[/ b] [/ b]
C ++ 11中的措辞是相似的,从C ++ 11到C ++ 14的变化反映在缺陷报告712 。
在C ++ 11之前,它是有点复杂,但原则上对于这种情况也是一样的。
I am a bit confused by the
static
in-class initialization of aconst
member. For example, in the code below:#include <iostream> struct Foo { const static int n = 42; }; // const int Foo::n; // No ODR void f(const int& param) { std::cout << param << std::endl; } int g(const int& param) { return param; } template<int N> void h() { std::cout << N << std::endl; } int main() { // f(Foo::n); // linker error, both g++/clang++ std::cout << g(Foo::n) << std::endl; // OK in g++ only with -O(1,2 or 3) flag, why?! h<Foo::n>(); // this should be fine }
I do not define
Foo::n
(the line is commented). So, I expect the callf(Foo::n)
to fail at link time, and indeed it does. However, the following linestd::cout << g(Foo::n) << std::endl;
compiles and links fine only by gcc (clang still emits a linker error) whenever I use an optimization flag such as-O1/2/3
.
- Why does gcc (tried with gcc5.2.0 and gcc 4.9.3) compile and link the code when the optimization is turned on?
- And am I correct to say that the only usage of in-class static const members is in constant expressions, such as template parameters like in the
h<Foo::n>
call, in which case the code should link?
解决方案ODR violations do not require a diagnostic, from the draft C++ standard standard section
3.2
[basic.def.odr] (emphasis mine going forward):Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.
So inconsistent behavior at different optimization levels is perfectly conformant behavior.
Informally a variable is odr-used if:
its address is taken, or a reference is bound to it, and a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.
So both
f
andg
will be odr-uses and require a definition.The relevant C++14 quote on odr-use would be from section [basic.def.odr]:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression [...]
The wording in C++11 is similar, the changes from C++11 to C++14 are reflected in defect report 712.
Before C++11 it is a bit more complicated but in principle the same for this case.
这篇关于在类static const ODR中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!