对shared_ptr中的const int的未定义引用

时间:2017-10-13 03:24:23

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

我有一个Config类

// config.hpp

class Config {
  public:
    static constexpr int a = 1;
    static constexpr int b = 1;
}

并包含在main.cpp

// main.cpp
#include "config.hpp"
int main () {
  std::cout << Config::a << std::endl; // this is ok
  std::shared_ptr<otherClass> stream = std::make_shared<otherClass>( 
Config::a); // compile error
}

和编译器说undefined reference to Config::a

并且在使用cout时有效,但在shared_ptr构造函数内无效。

我不知道为什么会这样。

2 个答案:

答案 0 :(得分:7)

请注意,std::make_shared通过引用获取参数,这会导致Config::aodr-used,因为它将绑定到引用参数,然后在命名空间范围内定义它是必需的(在C ++ 17之前)。

另一方面,std::cout << Config::a不会导致Config::a被使用,因为std::basic_ostream::operator<< (int)按值获取参数,Config::a则受制于Config::a要求复制初始化参数的左值到右值转换,因此constexpr int Config::a; // only necessary before C++17 不会被使用。

如果对象使用了odr,则其定义必须存在。您可以将定义(在实现文件中)添加为

static

请注意,它不能有初始化程序。

LIVE

由于C ++ 17 constexpr static data member是隐式内联的,因此不再需要这样的定义,因此您的代码在C ++ 17中运行良好。

  

如果constexpr数据成员被声明为inline,则它是隐式{{1}},并且不需要在命名空间范围内重新声明。这种重新声明没有初始化程序(以前需要如上所示)仍然是允许的,但已被弃用。

LIVE

答案 1 :(得分:1)

你的a是私有的,或者是public:需要在它之前或者使类成为一个结构来获取默认公共。但是这在C ++ 14下编译 https://godbolt.org/g/tS4M1Z

#include <iostream>
#include <memory>

struct Config {
  static constexpr int a = 1;
  static constexpr int b = 1;
};

struct otherClass {
    otherClass( int c ) { }
};

int main () {
  std::cout << Config::a << std::endl; // this is ok
  std::shared_ptr<otherClass> stream = std::make_shared<otherClass>( Config::a ); // compile error
}