何时定义类的静态数据成员(un /-)必要

时间:2018-08-24 11:45:22

标签: c++ static c++14 undefined-reference

我有一个大项目,正在努力进行重构。主要任务是重写记录器。新的记录器(据我所知)与旧的API兼容,因此我相信在更改标头包括目录之后,重新编译并重新链接一切都应该起作用。但不是。我收到多个undefined reference to <static_data_member>类型的错误。我无法粘贴实际代码,但看起来像这样:

// Foo.h
class Foo {
    static const int bar = 0;
    int baz; // assigned in c-tor
    void updateBaz() { baz = bar; }
    // ....
}

static const int bar在Foo.cpp中未定义。有时它是由日志宏打印的。它曾经可以使用(与旧的记录器一起使用),现在我必须对其进行定义。可能引起什么变化?

另一个由boost声明的变量发生的示例:

(...)/blog_adaptor.h:50: error: undefined reference to bbost::serialization::version<CA::CReyzinSignature>::value'

所以:什么时候需要静态成员的定义?什么时候可以省略它们?

2 个答案:

答案 0 :(得分:2)

除非将变量声明为inline(C ++ 17的一项功能),否则就C ++标准而言,静态成员变量的定义不是可选。无法提供定义是未定义的行为。

编译器和链接器可能会因使检查它们是否存在定义而有所不同,但这就是未定义行为的本质。

答案 1 :(得分:0)

正如Nicol Bolas回答的那样,我的项目中的代码具有未定义的行为,因为静态数据成员已初始化但未定义。总结和扩展: 在以下情况下,无需定义静态数据成员:

  • 它不使用或仅在废弃的分支(未实例化的模板和constexpr-if的废弃分支)中使用
  • 在C ++ 17中,如果成员为内联
  • clang-tidy还说“ constexpr静态数据成员的脱机定义在C ++ 17中是多余的,不建议使用”,因此静态constexpr也可能不需要它

此外,以下代码显示了为什么我的错误项目之前没有触发链接器错误。我不知道是不是“滥用毒品”还是“还没有伤害您的不确定行为”:

#include <boost/serialization/version.hpp>
class Klass {};
//BOOST_CLASS_VERSION(Klass, 3);
// would be expanded to:
namespace boost { namespace serialization {
template<>
struct version<Klass> {
    static const int value = 3; // not defined anywhere
};
} }

int foo (int val) { // was used by old logger
    return val;
}
int bar (const int &val) { // is used by new logger
    return val;
}
int main () {
//    return bar(boost::serialization::version<Klass>::value); // link error
    return foo(boost::serialization::version<Klass>::value); // works fine
}

因此,如果使用成员,则不会出现链接错误,但不会查询其地址。通过引用传递值符合查询地址的条件。