如果在函数模板中声明了本地类依赖吗?

wil*_*llj 5 c++ templates typename language-lawyer local-class

当前的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
}
Run Code Online (Sandbox Code Playgroud)

如果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标准的阅读,这个例子是完善的.

这种行为似乎包含在以下措辞中:

[temp.dep.type]/8

如果是,则类型依赖于

  • 模板参数,

  • 一个未知专业的成员,

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

  • 一个cv限定类型,其中cv-unqualified类型依赖于,

  • 由任何依赖类型构成的复合类型,

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

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

  • 由decltype(表达式)表示,其中表达式是类型依赖的.

但是,根据[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
}
Run Code Online (Sandbox Code Playgroud)

如果A<C>现在被视为依赖?

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

然而:

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

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

因此,如果定义按照dyp 的示例完成,C则将是依赖的,因为它是从 构造的T。
注释部分正在讨论的标准措辞中存在不明确之处,例如关于依赖的成员函数的定义T以及如何转换为类依赖项。