我有以下 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 可以很好地编译和链接此代码。另一方面,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)
哪个是对的?这段代码合法不合法?我对静态 constexpr 成员规则的理解(主要基于这个问题 https://stackoverflow.com/questions/22027228/c-static-constexpr-member-redeclaration-outside-of-class)是只有当获取变量的地址时才需要类外定义。但我不会获取 Derived::info 的地址或在任何地方使用对其的引用;我只是将其按值传递给 Base 构造函数。
我发现的各种解决方法:
- 将两个构造函数(基类和派生类)设置为 constexpr。这可能是也可能不是真实类的选项,真实类比示例中的类更复杂。无论如何,我要尝试一下。
- 在 main 中声明 Derived 实例,并使用自动持续时间而不是静态持续时间。这不是实际项目的选项:派生类是一个插件实现,需要将其实例导出为共享对象中的公共符号。
- 完全删除 Derived::info 并使用大括号初始化的临时对象调用 Base 构造函数,即
Base ({"Foobar", 2})
。这个解决方案可以工作,但随着更多成员被添加到 struct Info 中,它会变得丑陋(在我看来)。
啊哈,看来问题是隐含的Info(const Info &)
复制构造函数。为了通过const Info &
引用该构造函数,需要获取 Derived::info 的地址。
显然,GCC 在优化复制构造函数方面比 Clang 更积极。如果我使用-fno-elide-constructors
,然后 GCC 还抱怨对 Derived::info 的未定义引用。
无论如何,将 Base 和 Derived 构造函数声明为 constexpr 似乎完成了我想要在这里发生的事情,即在编译时初始化 Base::info,而不是在运行时从单独的 Derived::info 复制。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)