【问题标题】:undefined reference to const int within shared_ptrshared_ptr 中对 const int 的未定义引用
【发布时间】:2017-10-13 03:24:23
【问题描述】:

我有一个配置类

// 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 构造函数中无效。

我不知道为什么会这样。

【问题讨论】:

  • 你需要像c++17之前的静态成员一样在命名空间范围内定义a,即constexpr int Config::a;
  • 为什么cout 有效?
  • 这是完美转发和 odr 使用的不幸结果,导致 make_shared 不起作用。 make_shared&lt;otherClass&gt;(int(Config::a)) 也可以使用
  • 好的。希望你详细解释一下。谢谢!

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


【解决方案1】:

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

另一方面,std::cout &lt;&lt; Config::a 不会导致 Config::a 被 odr 使用,因为 std::basic_ostream::operator<< (int) 按值获取参数,Config::a 然后受请求的左值到右值转换复制-初始化参数,因此Config::a 不被使用。

如果一个对象是 odr-used,它的定义必须存在。您可以将定义(在实现文件中)添加为

constexpr int Config::a; // only necessary before C++17

注意它不能有初始化器。

LIVE

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

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

LIVE

【讨论】:

  • 注意命名空间范围的定义不能在头文件中;它必须在与其他所有内容链接的 .cpp 文件中。
【解决方案2】:

您的 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
}

【讨论】:

  • 是的,这个问题实际上可能与多个翻译单元有关。如果 otherClass 的构造函数在不同的 cpp 文件中,那么这在 C++14 中将不起作用。
猜你喜欢
  • 1970-01-01
  • 2011-07-20
  • 1970-01-01
  • 2020-09-17
  • 2014-10-18
  • 2013-07-01
  • 1970-01-01
相关资源
最近更新 更多