在clang / llvm 3.6.2中,以下代码在使用std=c++11
进行编译时导致编译错误:
template <typename T=void>
class bar
{
public:
struct foo
{
int array[10];
};
int baz()
{
return sizeof(foo::array);
}
};
int main(void)
{
bar<> b;
return b.baz();
}
命令行调用:
$ clang++ -std=c++11 nonstatic.cpp -o nonstatic
nonstatic.cpp:12:28: error: invalid use of non-static data member 'array'
return sizeof(foo::array);
~~~~~^~~~~
nonstatic.cpp:20:14: note: in instantiation of member function
'bar<void>::baz' requested here
return b.baz();
如果我将bar
更改为不再是模板,请参阅
class bar
{
public:
struct foo
{
int array[10];
};
int baz()
{
return sizeof(foo::array);
}
};
int main(void)
{
bar b;
return b.baz();
}
然后代码干净利落地编译。值得注意的是,GCC 5.2.1接受std=c++11
下的两个版本。另外值得注意的是,将array
移动到封闭的类模板主体中(但将其作为模板)也会导致clang接受此操作。
哪种行为相对于标准是正确的?这是GCC,clang或两者中的错误吗?
(我在cfe-users上问了同样的question,但到目前为止还没有得到回应。)
答案 0 :(得分:7)
这肯定是一个铿锵的错误; sizeof
表达式的操作数是 id-expression ,表示非静态数据成员,因此 [expr.prim.general] / 13成立。这是一个简化的例子:
template<class T> struct M { int f() { return sizeof(T::x); } };
struct S { int x; };
int main() { return M<S>{}.f(); }
当在模板实例方法中的未评估上下文中访问依赖类型成员时,将显示该错误。 Clang对n2253 rule enabling the use of non-static data members in unevaluated context(以及后来的改进)的实现看起来相当脆弱,并且与模板的交互很糟糕;类似(虽然不同)的错误是http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20151019/141535.html。
我找不到任何迹象表明已经向Clang Bugzilla报告了这一点;你可能想要开一个新的bug。
根据您的具体情况,解决方法可能包括在实例方法之外移动静态类型和值计算;值得注意的是,甚至使baz
static
成员函数足以说服clang接受您的代码。