【问题标题】:Is it required to specify the template argument of a base class if the base class is a parameter type of a member function?如果基类是成员函数的参数类型,是否需要指定基类的模板参数?
【发布时间】:2026-01-02 12:45:01
【问题描述】:

以下代码被 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;
}

【问题讨论】:

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


【解决方案1】:

我的第一直觉是说 VC++ 是正确的。在B 中查找名称A 应该会在A&lt;T&gt; 中找到injected-class-name A,它也可以用作type-name 参考A&lt;T&gt;

C++11 [temp.local]:

1 与普通(非模板)类一样,类模板具有注入类名称(第 9 条)。注入的类名可以用作 template-nametype-name。 当它与 template-argument-list 一起使用时, 作为模板模板参数的模板参数,或作为详细类型说明符中的最终标识符 在友元类模板声明中,它指的是类模板本身。否则等价 到 template-name 后跟 &lt;&gt; 中包含的类模板的 template-parameters

2 ...

3 类模板的注入类名或类模板特化可以用作 模板名type-name,无论它在范围内。 [ 例子:

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&lt;T&gt;的范围内,这取决于B的模板参数@ 987654331@,因此在非限定名称查找期间搜索。支持这一点的次要证据是 [temp.local] 中的示例使用 Derived::Base 而不仅仅是 Base

所以总的来说,我会这么说

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

  2. clang 不检查A&lt;T&gt;的范围其实是对的

【讨论】:

  • 14.6.1/3(在 n3337 中,如果相关)
  • @jrok 谢谢,正在看。但是,我最终不得不根据 14.6.2/3 重新制定我的结论
【解决方案2】:

Clang 是正确的;尽管类模板Ainjected-class-nameA&lt;T&gt; 中肯定可见,在派生类B&lt;T&gt; 中也可见,但它是一个依赖名称,因此在B&lt;T&gt; 中不会检查基类范围。

从属名称基类范围查找在 14.6.2p3 中讨论:

在类或类模板的定义中,如果一个基类依赖于一个模板参数,那么在非限定名称查找期间,无论是在定义类模板或成员,或在类模板或成员的实例化期间。

【讨论】:

    最近更新 更多