在离线成员定义的类型说明符中可以省略typename吗? [英] Can typename be omitted in the type-specifier of an out of line member definition?

查看:217
本文介绍了在离线成员定义的类型说明符中可以省略typename吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在测试clang是否需要 typename 时,我遇到了这种奇怪的行为。

I ran into this strange behaviour when testing whether or not typename is required by clang. Both clang and gcc accept this code while msvc rejects it.

template<class T1>
struct A
{
    template<class T2>
    struct B
    {
        static B f;
        static typename A<T2>::template B<T1> g;
    };
};

template<class T1>
template<class T2>
typename A<T2>::template B<T1> // ok, typename/template required
    A<T1>::B<T2>::g;

template<class T1>
template<class T2>
A<T1>::B<T2> // clang/gcc accept, msvc rejects missing typename
    A<T1>::B<T2>::f;

通常,限定ID A< T1> :: B& T2> (其中 A< T1> 是从属名称)应该被写为 typename A< T1& B< T2> 。 gcc / clang的行为是不正确的,还是在这种特殊情况下,一般规则(下面引用)有一个例外?

In general, a qualified-id A<T1>::B<T2> (where A<T1> is a dependent name) should be written typename A<T1>::template B<T2>. Is the behaviour of gcc/clang incorrect, or is there an exception to the general rule (quoted below) in this particular case?

可以说, A< T1> 不是依赖名称,或 B 是指当前实例化的成员。然而,在解析类型说明符的时候,不可能知道当前实例化是 A 。要求实现猜测 A< T1> 是当前实例化,似乎有问题。

It could be argued that A<T1> is not a dependent name, or that B<T2> refers to a member of the current instantiation. However, at the point of parsing the type-specifier it's not possible to know that the current instantiation is A<T1>. It seems problematic to require the implementation to guess that A<T1> is the current instantiation.


14.6名称解析[temp.res]

14.6 Name resolution [temp.res]

在模板声明或定义中使用的名称,它取决于模板参数:
假设不命名类型,除非适用的名称查找找到类型名称或该名称由关键字typename限定为

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

14.2模板特化的名称[ temp.names]

14.2 Names of template specializations [temp.names]

成员模板专用化的名称出现在 - > 在后缀表达式中或在
之后嵌套名称说明符在限定id,以及后缀表达式的对象或指针表达式或
qualified-id中的nested-name-specifier取决于模板参数(14.6.2),但是不引用当前实例化(14.6.2.1)的
成员,成员模板名称必须以关键字
模板。

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object or pointer expression of the postfix-expression or the nested-name-specifier in the qualified-id depends on a template parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

为了进一步调查这里做什么,我也尝试过: / p>

To further investigate what clang is doing here, I also tried this:

template<class T1>
struct C
{
    template<class T2>
    struct D
    {
        static typename A<T1>::template B<T2> f;
        static typename A<T1>::template B<T2> g;
    };
};

template<class T1>
template<class T2>
typename A<T1>::template B<T2> // ok, typename/template required
    C<T1>::D<T2>::f;

template<class T1>
template<class T2>
A<T1>::B<T2> // clang rejects with incorrect error
    C<T1>::D<T2>::g;

Clang提供错误:使用不同类型重新定义'g' code>,但是 g 的类型实际上与声明匹配。

Clang gives error: redefinition of 'g' with a different type, but the type of g actually matches the declaration.

一个诊断建议使用 typename 模板

推荐答案

MSVC是正确的。

我对C ++ 11标准的阅读表明,需要 typename

My reading of the C++11 standard suggests that typename is required.

如果没有 typename 关键字,则假定依赖名称不能命名类型。

Without the typename keyword, a dependent name is assumed not to name a type.


14.6名称解析[temp.res]

14.6 Name resolution [temp.res]

2)
模板声明或定义,并且依赖于模板参数
假定不命名一个类型,除非适用的名称查找找到一个类型名称或名称由关键字typename限定为

2) A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

3)
当限定id用于引用不是当前实例化的成员的类型
及其嵌套名称说明符指的是依赖类型,应以关键字typename为前缀。

3) When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename

7)
在类模板或
declarator-id
之后的类模板的成员,当引用声明类型的类模板的先前声明的
成员的名称时,不需要关键字typename。 [注意:这种名称可以使用不合格的名称
查找,类成员查找到当前实例化来找到,或者类成员访问
表达式查找当对象表达式的类型是当前实例化

7) Within the definition of a class template or within the definition of a member of a class template following the declarator-id, the keyword typename is not required when referring to the name of a previously declared member of the class template that declares a type. [Note: such names can be found using unqualified name lookup, class member lookup into the current instantiation, or class member access expression lookup when the type of the object expression is the current instantiation

14.6.2.1依赖类型[temp.dep.type]

14.6.2.1 Dependent types [temp.dep.type]

如果


  • 在主类模板或主类模板的成员的定义中,
    类模板的名称,后面是主模板的模板参数列表(如下所述)
    (包含在<>
  • 中)

A的成员的定义中使用 A< T1> ,它指的是当前实例化 。当解析 f 的定义时,由 A< T1> :: 限定的类型名可以通过类成员名称查找到当前实例化

When A<T1> is used in the definition of a member of A, it refers to the current instantiation. When parsing the definition of f a type name qualified by A<T1>:: can be found by class member name lookup into the current instantiation.

然而,当C ++解析器遇到 A< T1> 在返回类型的成员函数定义 - 在declarator-id之前 - 它还没有遇到封闭类的名称。解析器无法确定 A 是否指向此时的封闭类。

However, when the C++ parser encounters A<T1> in the return-type of a member function definition - before the declarator-id - it has not yet encountered the name of the enclosing class. The parser cannot determine whether or not A refers to the enclosing class at this point.

因为这个原因 - 无论是否 A< T1> 命名当前实例化 - 标准不允许在定义内省略 typename

For this reason - regardless of whether or not A<T1> names the current instantiation - the standard does not permit omission of typename within the definition of a member of a class template before the declarator-id.

example 由Vaughn Cato证明,Clang / GCC的行为不一致,并且在类似的情况下需要 typename

This example by Vaughn Cato demonstrates that the behaviour of Clang/GCC is inconsistent, and requires typename in a similar scenario:

template <typename T>
struct A {
    typedef int X;
    X f();
};

template <typename T>
A<T>::X A<T>::f() // error: missing 'typename'
{
}

这篇关于在离线成员定义的类型说明符中可以省略typename吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆