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


为什么 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;
}

4494
2018-05-27 05:43


起源



答案:


如你所说, emplace_back 通过引用获取参数,所以传递 base_trait::n 导致它 ODR使用的

如果一个对象的值被读取(除非它是一个编译时间常量)或写入,它的地址被采用,或者一个引用被绑定到它上面,它就是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起)


9
2018-05-27 05:52



那么右值引用需要一个定义以及左值引用吗? - mljli
@mljli它导致参数被使用;它与左值参考相同。在C ++ 17之前,这意味着需要定义。 Ater C ++ 17不再需要静态constexpr数据成员的定义,因此您的代码可以正常使用C ++ 17。 - songyuanyao
@mljli为什么你期望rvalue ref有所不同?使用时,两者都只是普通参考(左值)。 - curiousguy
@curiousguy我认为const左值引用和右值引用不需要定义。并且静态const成员可以仅用作文字,即没有存储/地址。 - mljli
@mljli你能发布一个你认为/应该/可能的参考的简单例子吗? 不 需要一个定义? - curiousguy


答案:


如你所说, emplace_back 通过引用获取参数,所以传递 base_trait::n 导致它 ODR使用的

如果一个对象的值被读取(除非它是一个编译时间常量)或写入,它的地址被采用,或者一个引用被绑定到它上面,它就是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起)


9
2018-05-27 05:52



那么右值引用需要一个定义以及左值引用吗? - mljli
@mljli它导致参数被使用;它与左值参考相同。在C ++ 17之前,这意味着需要定义。 Ater C ++ 17不再需要静态constexpr数据成员的定义,因此您的代码可以正常使用C ++ 17。 - songyuanyao
@mljli为什么你期望rvalue ref有所不同?使用时,两者都只是普通参考(左值)。 - curiousguy
@curiousguy我认为const左值引用和右值引用不需要定义。并且静态const成员可以仅用作文字,即没有存储/地址。 - mljli
@mljli你能发布一个你认为/应该/可能的参考的简单例子吗? 不 需要一个定义? - curiousguy