make_shared 对已初始化静态成员变量的未定义引用

Undefined reference to initialized static member variable with make_shared

使用-std=c++14编译以下代码:

#include <memory>

class A
{
public:
    static constexpr int c = 0;
    std::shared_ptr<int> b;

    A()     {
        b = std::make_shared<int> (c);
    }

};

int main () {
    A a;
    return 0;
}

给出链接器错误“对 `A::c' 的未定义引用”,而在不是“make_shared”的其他上下文中使用“A::c”时,不会发生此错误。特别是,以下代码可以正确编译和工作:

class A
{
public:
    static constexpr int c = 0;
    std::shared_ptr<int> b;

    A()     {
        int cc = c;
        b = std::make_shared<int> (cc);
    }

};

从 C++17 开始,第一个代码应该可以正常工作:static constexpr class 成员变量是隐式的 inline,这意味着编译器负责确保定义存在。

在 C++17 之前,由于 ODR 违规,代码具有未定义的行为(不需要诊断)。 odr-used 的静态 class 成员还必须具有外联定义。

将引用绑定到变量算作 odr-usemake_shared<int>(c) 会发生这种情况,因为该函数定义为:

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

因此参数绑定到引用参数。


理论上你应该可以使用 make_shared<int>(+c) 解决它...然后引用绑定到 +c 的临时结果而不是 c 本身,因此没有 ODR 使用。与您在问题中发布的解决方法类似的理论。

enum { c = 0 }; 是另一种可能的解决方法,如果实际代码中的类型是 int .