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

时间:2014-12-29 12:04:41

标签: c++ templates language-lawyer typename 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
}

如果省略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-qualified类型依赖的cv限定类型,

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

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

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

  •   
  • 由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
}

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

3 个答案:

答案 0 :(得分:4)

根据我的理解(以及标准的当前措辞),您的示例中的C不依赖。这两项都不是A<C>::Type,因此不需要typename

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

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

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

然而:

  

如果类型是

,则类型是依赖的      
      
  • 由任何依赖类型构建的复合类型,
  •   

因此,如果定义是在dyp's example中完成的,那么C将依赖T构建。 在评论部分讨论的标准措辞中存在不明确之处,例如:关于依赖于T的成员函数的定义以及如何转换为类依赖项。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

标准中似乎没有任何内容表明此处需要typename关键字。这些措辞也没有明确说明,这可能导致海湾合作委员会采取一些捷径来处理f<T>(T)::C(在函数模板专业化中是一个本地类)依赖于T - 扩展,这会使A<[f<T>(T)::]C>::Type依赖。

Core defect 1484没有具体针对这个问题提出,但我认为它提出的其他非规范性文本使得意图明确,如果它是标准的,GCC将完全不需要{{1}这里有关键字。