In class static const ODR

只愿长相守 提交于 2019-11-30 09:18:24
Shafik Yaghmour

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 and g 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.

I suppose that the compiler performs the following actions during the optimization:

  • The value const static int n is inlined everywhere. No memory is allocated for the variable n, references to it becomes invalid. The function f() need a reference to n so the program is not compiled.

  • The function g is short and simple. It is effectively inlined and optimized. After the optimization, the function g does not need a reference to n, it just returns constant value 42.

The solution is to define the variable outside the class:

struct Foo
{
    const static int n;
};

const int Foo::n = 42;

Formally, ODR violations are undefined behaviour, so the compiler may exhibit any behaviour it likes. That's why the behaviour changes with optimization level and compiler- the compiler has no obligation to maintain a particular behaviour.

Nevermore

There is no definition at all. GCC 4.9.2 doesn't compile and link that with any flags.

Note, that:

const static int n = 42;

is a declaration and initializer, but not a definition.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!