5

当前的 C++ 编译器(最新的 gcc、clang)需要typename以下示例中的关键字:

template<class T>
struct A
{
};

template<class T>
void f(T)
{
    struct C
    {
    };
    typedef typename A<C>::Type Type; // typename required
}

如果typename省略 gcc (4.9, 5.0) 会报错:

need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope

根据我对 C++11 标准的阅读,此示例的格式正确。

以下措辞似乎涵盖了此行为:

[温度.dep.type]/8

一个类型是依赖的,如果它是

  • 模板参数,

  • 未知专业的成员,

  • 作为当前实例化成员的嵌套类或枚举,

  • 一个 cv 限定类型,其中 cv 非限定类型是依赖的,

  • 从任何依赖类型构造的复合类型,

  • 由任何依赖类型构造的数组类型,或者其大小由依赖于值的常量表达式指定,

  • 一个 simple-template-id,其中模板名称是模板参数或任何模板参数是依赖类型或依赖于类型或值的表达式,或

  • 由 decltype(expression) 表示,其中 expression 取决于类型。

但是,根据 [class.local],该类C本地类而不是嵌套类。如果是这样,为什么要A<C>被视为依赖?

编辑

对于奖励积分,如果通过添加成员枚举来修改示例C,如下所示:

template<typename T>
struct A
{
    typedef T Type;
};

template<class T>
void f(T)
{
    struct C
    {
        enum { value = T::value };
    };
    typedef typename A<C>::Type Type; // typename required
}

现在应该A<C>被视为依赖?

4

3 回答 3

4

根据我的理解(和标准的当前措辞),C在你的例子中是不依赖的。也不是A<C>::Type,所以typename不需要。

类模板的嵌套类和函数模板中的本地类之间有一个根本的区别:后者不能被特化,因此对函数模板内的本地类的任何引用都是统一的。也就是说,在 的每个特化中f,都指在此函数模板中定义C的类。类模板并非如此,因为您确实可以自己明确地专门化成员(如 [temp.expl.spec] /(1.6) 中所述):Cf

template <typename T>
class A { class C{}; };

template <>
class A<int>::C { int i; };

然而:

一个类型是依赖的,如果它是

  • 从任何依赖类型构造的复合类型,

因此,如果定义如dyp 的示例中那样完成,C则将依赖于T.
评论部分正在讨论的标准措辞中存在不明确之处,例如关于依赖的成员函数的定义T以及如何转换为类依赖。

于 2014-12-29T13:03:57.697 回答
0

标准中似乎没有任何内容表明typename此处必须使用关键字。措辞也没有明确说明,这可能导致 GCC 在将f<T>(T)::C(作为函数模板专业化中的本地类)视为依赖时采取了一些捷径T——通过扩展,这将使A<[f<T>(T)::]C>::Type依赖。

核心缺陷 1484并未专门针对此问题提出,但我认为它提出的附加非规范性文本明确了意图,如果它在标准中,GCC 将不要求typename此处的关键字。

于 2014-12-29T13:31:43.500 回答
0

以下是我的推理,希望对您有所帮助。本地C不实例化,直到f实例化。因此,A<C>它不是实例化,并且在编译器看到它时是不透明的。由于不透明性,编译器无法确定A<C>::Type是嵌套类型名称还是数据成员或方法。但是,默认情况下,编译器不会将A<C>::Type其视为嵌套类型名称。因此,需要一个明确的规范。

于 2014-12-29T12:32:28.490 回答