在以下示例中,gcc 5.0和clang 3.6都需要typename关键字:

template<typename T>
struct B
{
    typedef int Type;
};

template<int n>
struct A
{
    typedef typename B<decltype(throw (int*)n)>::Type Throw;
    typedef typename B<decltype(delete (int*)n)>::Type Delete;
};

C++ 11标准中的以下措辞涵盖了这一点:



因此,我假设在两种情况下decltype都会生成void



这表明涉及throwdelete的表达式不能为常量表达式。



因此,B<decltype(..)>仅在表达式依赖类型时才依赖。



这表明两个表达式都不能依赖于类型。

gcc和clang都错了吗?

最佳答案

让我们回到需要typename的时候。 §14.6[temp.res]/p3,所有引号均来自N4140:



在这种情况下,qualified-id是B<decltype(throw (int*)n)>::Type(和delete版本,其分析是完全相同的)。因此,如果nested-name-specifier或typename引用从属类型,则B<decltype(throw (int*)n)>::是必需的。

§14.6.2.1[temp.dep.type]/p8指出,省略了六个无关的项目符号,


B<decltype(throw (int*)n)>是一个简单模板ID。模板名称B不是模板参数。唯一的模板参数decltype(throw (int*)n)不是表达式,因此,只有B<decltype(throw (int*)n)>是从属类型时,decltype(throw (int*)n)才是从属的。反之,按照子弹8.8,decltype(throw (int*)n)仅在throw (int*)n是类型相关的情况下才是相关的。但是我们知道,根据§14.6.2.2[temp.dep.expr]/p4:



因此,throw (int*)n不依赖类型,因此decltype(throw (int*)n)不是依赖类型,因此B<decltype(throw (int*)n)>不是依赖类型,因此typename不需要B<decltype(throw (int*)n)>::Type,所以是的,这是一个编译器错误。

关于c++ - 抛出或删除表达式是否可以依赖?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27713666/

10-13 08:36