如果基类是成员函数的参数类型,是否需要指定基类的模板参数?

时间:2014-06-19 13:13:40

标签: c++ templates visual-c++ clang standards

以下代码被VC ++ 2013接受,但被clang 3.4拒绝。

根据C ++标准,哪个编译器是正确的?

template<class T>
struct A
{
    T n;
};

template<class T>
struct B : A<T>
{
    // VC++ 2013 : OK
    // clang : error : use of class template 'A' requires template arguments
    B& f1(const A& obj) 
    {
        return *this;
    }

    // VC++ : OK
    // clang : OK
    B& f2(const A<T>& obj)
    {
        return *this;
    }
};

int main()
{
    B<int> b;
}

2 个答案:

答案 0 :(得分:14)

我的第一直觉是说VC ++在这一方面是正确的。在A中查找名称B应该会在A中找到注入类名称 A<T>,它也可以用作< em> type-name 以引用A<T>

C ++ 11 [temp.local]:

  

1与普通(非模板)类一样,类模板具有注入类名(第9节)。 inject-class-name可以用作模板名称类型名称。当它与 template-argument-list一起使用时,< / em>作为模板模板参数的模板参数 elaborated-type-specifier 中的最终标识符   朋友类模板声明,它指的是类模板本身。否则,它是等价的   到 template-name 后跟<>中包含的类模板的 template-parameters

     

2 ...

     

3类模板或类模板特化的注入类名称可用作模板名称   或类型名称,只要它在范围内。 [示例:

template <class T> struct Base {
  Base* p;
};

template <class T> struct Derived: public Base<T> {
  typename Derived::Base* p; // meaning Derived::Base<T>
};

然而,与此同时,[temp.dep]§3指出:

  

3在类或类模板的定义中,如果基类依赖于模板参数,基类   在类模板的定义点处,在非限定名称查找期间不会检查范围   或成员或在类模板或成员的实例化期间。

基于此,我更倾向于说clang实际上是正确的,因为注入的类名AA<T>的范围内,这取决于B }的模板参数T因此在非限定名称查找期间搜索。支持这一点的次要证据是[temp.local]中的示例使用Derived::Base而不是Base

总的来说,我会说

  1. 这是一个很好的角落案例,

  2. clang实际上没有检查A<T>的范围

答案 1 :(得分:5)

Clang是对的;虽然类模板A注入类名A<T>中肯定可见,并且在派生类B<T>中可见,但它是 dependent name,因此不会在B<T>中检查基类范围。

依赖名称基类范围查找在14.6.2p3中讨论:

  

在类或类模板的定义中,如果基类依赖于模板参数,则在非限定名称查找期间,不会在定义时检查基类作用域。类模板或成员,或者在类模板或成员实例化期间。