其他分享
首页 > 其他分享> > c – 静态constexpr变量使用了odr吗?

c – 静态constexpr变量使用了odr吗?

作者:互联网

给出下面的代码,是否使用Foo :: FOO1 ODR?

#include <iostream>
#include <map>
#include <string>

class Foo
{
public:
    static constexpr auto FOO1 = "foo1";
    void bar();
};

void Foo::bar()
{
    const std::map<std::string, int> m = {
        {FOO1, 1},
    };
    for (auto i : m)
    {
        std::cout << i.first << " " << i.second << std::endl;
    }
}

int main()
{
    Foo f;
    f.bar();
    return 0;
}

使用-O1或更高版本编译代码,没关系,但是如果用-O0编译,我会得到以下错误(参见coliru example

undefined reference to `Foo::FOO1'

表示它是ODR使用的.这是什么?

我知道上面的代码用-O构建得很好,但是在a real (and more complex) case

>代码编译并与-O2良好链接
>代码获取上面未定义的引用错误LinkTimeOptimization(-O2 -flto)

所以它表明优化(-O)和LinkTimeOptimization(-flto)都会影响ODR使用规则?这是否在C 14和C 17之间发生变化?

解决方法:

规则是[basic.def.odr]/4

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial 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 ([conv.lval]) is applied to e, or e is a discarded-value expression ([expr.prop]).

第一部分显然是满意的(FOO1是constexpr,所以左值到右值的转换确实产生一个常量表达而不调用非平凡的函数),但是第二部分呢?

我们正在构建一张地图.相关的constructor there采用initializer_list< value_type>,也就是说initializer_list< pair< const string,int>>. pair有一个bunch of constructors,但是这里要调用的是:

template <class U1, class U2>
constexpr pair(U1&& x, U2&& y); // with U1 = char const*&, U2 = int

这里重要的部分是我们不是直接构造一个字符串,我们正在经历这个对的转换构造函数,它涉及绑定对FOO1的引用.这是一种奇怪的用法.这里没有左值到右值的转换,也不是丢弃值表达式.

基本上,当你拿一些东西的地址,这是一种使用 – 它必须有一个定义.所以你必须添加一个定义:

constexpr char const* Foo::FOO1;

另请注意,这个:

std::string s = FOO1;

不会是一种奇怪的用途.这里我们直接调用一个构造函数来获取char const *参数,这将是一个左值到右值的转换.

在C 17中,我们在[dcl.constexpr]得到了这个新句子:

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable ([dcl.inline]).

这并没有改变任何关于odr-use的东西,FOO1仍然在你的程序中使用.但它确实使FOO1隐式地成为内联变量,因此您不必为其明确添加定义.很酷.

另请注意,仅仅因为程序编译和链接并不意味着缺少定义的变量不会被使用.

So it indicates that both optimizations (-O) and LinkTimeOptimization (-flto) would affect ODR-use rule?

他们不.优化很酷.

标签:one-definition-rule,c,c14
来源: https://codeday.me/bug/20190823/1697258.html