以下代码片段在g++和clang++下运行良好:
// bsp1.cc
class A {
public:
A(int, char const *);
int value;
const char * name;
};
class B {
public:
static const A many_as[];
};
A const B::many_as[]
{ { 0, "zero" },
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 77, 0 } };
当我将B类更改为模板时:
// bsp2.cc
class A {
public:
A(int, char const *);
int value;
const char * name;
};
template<typename T>
class B {
public:
static const A many_as[];
};
template<>
A const B< int >::many_as[]
{ { 0, "zero" },
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 77, 0 } };
clang++在以下方面失败:
tmp/bsp2.cc:19:1: error: expected ';' after top level declarator
{ { 0, "zero" },
^
1 error generated.
g++仍然对此感到满意。
版本信息: g++ (Debian4.7.2-4) 4.7.2,clangVersion3.3(主干171722)
当我将=
添加为
A const B< int >::many_as[] =
clang++也很高兴。
我的问题:
=
之间有什么语义上的区别吗?(也就是说,我可以使用=
的版本作为“解决办法”吗?)发布于 2013-01-14 13:41:26
9.4.2p2指定非模板静态数据成员的定义;隐含地说,它的语法与任何其他定义相同,因此大括号或等号初始化器的大括号列表是绝对好的。14p1和14.5.1.3涵盖了模板静态数据成员的显式专门化的定义,并且通过暗示,静态数据成员的任何有效定义对于模板静态数据成员显式专门化的定义都是有效的。
实际上,14.7.3p13显式演示了在模板静态数据成员显式专门化中使用大括号-init-list来区分默认初始化和定义:
struct X {};
template<typename> struct Q { static X i; };
template<> X Q<int>::i{};
因为clang不能接受标准中的示例中的这个语法,所以很明显,bug是在clang中的。
在这种情况下,您的解决方法是绝对有效的。插入=
的语义含义(8.5p14)是直接初始化(8.5p16)变为复制初始化(8.5p15)。由于您的初始化程序是一个带括号的init列表(8.5p17),所以执行列表初始化(8.5.4),并且从直接列表初始化更改为复制列表初始化(8.5.4p1),但是由于您的对象是一个数组,因此是一个聚合(8.5.1p1),因此将执行聚合初始化,这是对直接/复制初始化区别视而不见的。
注意,A
上存在一个构造函数,这使得它不能成为一个聚合,这意味着可能在运行时调用构造函数。如果您删除了构造函数,那么A
数组将是一个递归聚合,可以在编译时完全初始化(数据将直接放置到您的对象文件中)。
https://stackoverflow.com/questions/14318426
复制相似问题