简体   繁体   English

静态constexpr类成员何时需要类外定义?

[英]When does a static constexpr class member need an out-of-class definition?

I have the following C++11 code (simplified version): 我有以下C ++ 11代码(简化版):

struct Info
{
    const char * name;
    int version;
};

class Base
{
public:
    const Info info;
    Base (Info info) : info (info) {}
};

class Derived : public Base
{
public:
    static constexpr Info info = {"Foobar", 2};
    Derived () : Base (info) {}
};

int main ()
{
    static Derived derived;
    return 0;
}

GCC 4.9.1 compiles and links this code fine. GCC 4.9.1编译并链接此代码很好。 Clang 3.5.0, on the other hand, complains about an undefined reference: 另一方面,Clang 3.5.0抱怨未定义的引用:

/tmp/test-109c5c.o: In function `main':
test.cc:(.text+0x1c): undefined reference to `Derived::info'
test.cc:(.text+0x22): undefined reference to `Derived::info'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Which is right? 哪个是对的? Is this code legal or not? 此代码合法吗? My understanding of the rules regarding static constexpr members (based mostly on this question ) is that an out-of-class definition is needed only when the address of the variable is taken. 我对有关静态constexpr成员的规则的理解(主要基于此问题 )是,仅当获取变量的地址时才需要类外定义。 But I'm not taking the address of Derived::info or using a reference to it anywhere; 但是我没有使用Derived :: info的地址,也没有在任何地方使用对它的引用。 I'm only passing it by value to the Base constructor. 我只是按值将其传递给Base构造函数。

Various workarounds that I've found: 我发现了各种解决方法:

  • Make both constructors (Base and Derived) constexpr. 使两个构造函数(基本和派生)都成为constexpr。 This may or may not be an option with the real classes, which are more complex than the ones in the example. 对于实际类,这可能是选项,也可能不是,这比示例中的复杂。 I'm going to try it, anyway. 无论如何,我都会尝试的。
  • Declare the instance of Derived in main with automatic rather than static duration. 用自动而不是静态持续时间声明派生于main的实例。 This is not an option for the real project: the Derived class is a plugin implementation, and an instance of it needs to be exported as a public symbol in a shared object. 对于实际项目而言,这不是一个选择:Derived类是一个插件实现,并且需要将其实例作为公共符号导出到共享对象中。
  • Remove Derived::info entirely and call the Base constructor with a brace-initialized temporary object instead, ie Base ({"Foobar", 2}) . 完全删除Derived :: info,并使用大括号初始化的临时对象(即Base ({"Foobar", 2})来调用Base构造函数。 This solution would work, but it gets ugly (in my opinion) as more members are added to struct Info. 该解决方案可以工作,但是(在我看来)随着更多的成员添加到结构信息中,它变得很难看。

Aha, it seems that the problem is the implicit Info(const Info &) copy constructor. 啊哈,看来问题出在隐式的Info(const Info &)复制构造函数。 To pass the const Info & reference to that constructor, it's necessary to take the address of Derived::info. 要将const Info &引用传递给该构造函数,必须获取Derived :: info的地址。

Apparently GCC is more aggressive than Clang in optimizing away the copy constructor. 显然,在优化复制构造函数方面,GCC比Clang更具攻击性。 If I use -fno-elide-constructors , then GCC also complains about an undefined reference to Derived::info. 如果我使用-fno-elide-constructors ,那么GCC也会抱怨对Derived :: info的未定义引用。

In any case, declaring the Base and Derived constructors as constexpr seems to accomplish what I want to happen here, which is to have Base::info initialized at compile time, rather than copied from a separate Derived::info at run time. 无论如何,将Base和Derived构造函数声明为constexpr似乎可以完成我想在这里完成的工作,即在编译时初始化Base :: info,而不是在运行时从单独的Derived :: info复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么类外成员模板定义需要重复其声明“requires-clause” - Why does an out-of-class member template definition need a repetition of its declaration 'requires-clause' 模板 class 的模板成员 function 的类外定义的语法 - Syntax of out-of-class definition of a template member function of a template class 为什么 constexpr 静态成员(类型类)需要定义? - Why does constexpr static member (of type class) require a definition? 具有类类型非类型模板参数的类模板成员的类外定义 - Out-of-class definition of member of a class template with a class-type non-type template parameter 模板类中的 C++20 类外定义 - C++20 out-of-class definition in a template class 专门的内部类模板的功能的外层定义? - Out-of-class definition of function of specialized inner class template? 是否需要静态变量的类外定义? - Need for out of class definition of static variable? 添加静态constexpr成员是否会更改结构/类的内存映射? - Does adding a static constexpr member change the memory mapping of a struct/class? 不可能在 function 定义的类外声明符中完全限定类名 - Impossible to fully qualify class-name in out-of-class declarator of function definition 带有静态constexpr成员的模板类的ODR - ODR of template class with static constexpr member
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM