【问题标题】:emplace_back causes link error on static constexpr memberemplace_back 导致静态 constexpr 成员上的链接错误
【发布时间】:2018-11-06 01:02:19
【问题描述】:

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

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

示例代码:

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;
}

【问题讨论】:

    标签: c++ language-lawyer c++17 constexpr one-definition-rule


    【解决方案1】:

    如您所说,emplace_back 通过引用获取参数,因此传递 base_trait::n 会使其成为 odr-used

    如果对象的值被读取(除非它是编译时常量)或写入、获取其地址或绑定到它的引用,则该对象是 odr-used;

    在 C++17 之前,这意味着这里需要 base_trait::n 的定义。但是从 C++17 开始,行为发生了变化,对于 constexpr static data member,不再需要类外定义。

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

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

    【讨论】:

    • 那么右值引用需要定义和左值引用一样吗?
    • @mljli 它导致参数被 odr-used;它与左值引用相同。在 C++17 之前,这意味着定义是必需的。在 C++17 之后,不再需要静态 constexpr 数据成员的定义,因此您的代码可以在 C++17 中正常工作。
    • @mljli 为什么你期望右值引用不同?使用时,两者都只是普通引用(左值)。
    • @curiousguy 我认为 const 左值引用和右值引用不需要定义。静态 const 成员只能用作文字,即没有存储/地址。
    • @mljli 您能否发布一个您认为是否/应该/可能需要定义的简单示例?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 2012-01-17
    • 1970-01-01
    • 2019-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多