emplace_back导致静态constexpr成员上的链接错误

mlj*_*jli 12 c++ one-definition-rule language-lawyer constexpr c++17

为什么emplace_back要引用需要定义的成员?emplace_back(integer literal)和之间有什么区别emplace_back(static constexpr integer member)

如果我切换到C++ 17,它编译得很好.我发现在C++ 17中,静态constexpr数据成员是隐式内联的.这是否意味着编译器隐式为它们创建定义?

示例代码:

class base {
    int n;
public:
    base(int n):n(n) {}
};

struct base_trait {
    static constexpr int n = 1;
};

int main(void) {
    vector<base> v;
    v.emplace_back(1);  // ok
    v.emplace_back(base_trait::n);  // link error with -std=c++14, ok with -std=c++17
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 9

如你所说,emplace_back通过引用获取参数,因此传递base_trait::n会导致它被使用.

如果一个对象的值被读取(除非它是一个编译时常量)或写入,它的地址被采用,或者一个引用被绑定,它就是odr-used;

在C++ 17之前,这意味着base_trait::n这里需要定义.但是,由于C++ 17的行为发生了变化,对于constexpr静态数据成员,不再需要类外定义.

如果const non-inline (since C++17)静态数据成员or a constexpr static data member (since C++11)使用odr,则仍需要命名空间作用域的定义,但它不能具有初始化程序.This definition is deprecated for constexpr data members (since C++17).

可以内联声明静态数据成员.可以在类定义中定义内联静态数据成员,并可以指定初始化程序.它不需要一个类外的定义.(自C++ 17起)

  • @mljli它导致参数被使用; 它与左值参考相同.在C++ 17之前,这意味着需要定义.Ater C++ 17不再需要静态constexpr数据成员的定义,因此您的代码可以正常使用C++ 17. (2认同)