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

时间:2016-03-09 20:07:58

标签: c++11 gcc clang language-lawyer 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();
}

命令行调用:

$ 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,但到目前为止还没有得到回应。)

1 个答案:

答案 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接受您的代码。