是非法获取嵌套在类模板中的`sizeof`结构的非静态成员吗​​?

Bob*_*tti 15 gcc clang language-lawyer c++11 clang++

在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();
}
Run Code Online (Sandbox Code Playgroud)

命令行调用:

$ 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();
Run Code Online (Sandbox Code Playgroud)

如果我改为bar不再是模板,就像在

class bar
{
public:
    struct foo
    {
        int array[10];
    };

    int baz()
    {
        return sizeof(foo::array);
    }
};

int main(void)
{
    bar b;
    return b.baz();
}
Run Code Online (Sandbox Code Playgroud)

然后代码干净利落地编译.值得注意的是,GCC 5.2.1接受两个版本std=c++11.另外值得注意的是,移入array封闭的类模板体(但将其作为模板)也会导致clang接受此操作.

相对于标准,哪种行为是正确的?这是GCC,clang或两者中的错误吗?

(我问过关于cfe用户的同样问题,但到目前为止还没有得到回复).

eca*_*mur 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(); }
Run Code Online (Sandbox Code Playgroud)

当在模板实例方法中的未评估上下文中访问依赖类型成员时,该错误就会展示.Clang实施的n2253规则允许在未评估的上下文(以及后来的改进)中使用非静态数据成员,这看起来相当脆弱,并且与模板交互不良; 一个类似(虽然不同)的错误是http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20151019/141535.html.

我找不到任何迹象表明已经向Clang Bugzilla报告过; 你可能想要开一个新的bug.

根据您的具体情况,变通方法可能包括在实例方法之外移动静态类型和值计算; 特别是即使bazstatic成员函数也足以说服clang接受你的代码.