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

xml*_*lmx 18 c++ standards templates clang visual-c++

以下代码被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;
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 14

我的第一直觉是说VC++在这一方面是正确的.名称的查询AB应该找到注射类名 AA<T>,这也可以作为一个类型名称来指代A<T>.

C++ 11 [temp.local]:

1与普通(非模板)类一样,类模板具有注入类名(第9节).inject-class-name可以用作模板名称类型名称.当它与template-argument-list一起使用时,作为模板模板参数的模板参数,或作为 友元类模板声明的详细类型说明符中的最终标识符,它引用类模板本身.否则,它等同于template-name,后跟括在其中的类模板的template-parameters<>.

2 ......

3类模板或类模板特化的inject-class-name可以用作模板名称类型名称,只要它在范围内.[ 例如:

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

template <class T> struct Derived: public Base<T> {
  typename Derived::Base* p; // meaning Derived::Base<T>
};
Run Code Online (Sandbox Code Playgroud)

但是,与此同时,[temp.dep]§3指出:

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

基于此,我更倾向于说clang实际上是正确的,因为inject-class-name A在范围内A<T>,这取决于B模板参数T,因此在非限定名称查找期间不会被搜索.支持这一点的次要证据是来自[temp.local]的例子Derived::Base而不仅仅是使用Base.

总的来说,我会说

  1. 这是一个很好的角落,并且

  2. clang实际上是不正确的检查范围 A<T>


eca*_*mur 5

铿锵是对的; 虽然注入的类名类模板的A距离肯定是可见A<T>和派生类中的那么明显B<T>,这是一个依赖名称等基础类的范围之内没有检查B<T>.

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

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