为什么通用模板方法定义与模板类专门化不匹配?

时间:2014-01-08 04:56:34

标签: c++ templates c++11

我有以下代码:

template <class T, class U = T>
class A {
  public:
    void f();
};

template <class T>
class A<T, T> {
  public:
    void f();  // Unaltered method.

    // Some differences.
};

template <class T, class U>
void A<T, U>::f() {}

int main() {
  A<int> a;
  a.f();
  return 0;
}

clang++ -std=c++11 test.cc给了我一个错误:undefined reference to 'A<int, int>::f()'

为什么提供的方法f()的定义不适用于班级A<int, int>

2 个答案:

答案 0 :(得分:6)

主要类模板template <class T, class U = T> class A和部分特化template <class T> class A<T, T>是两个不同的模板定义。在定义它们之后,无论何时引用类模板名称A,都将始终考虑主模板和所有部分特化。

每当使用单个模板参数或相同类型的两个参数实例化A时,它将与您提供的特化形成更好的匹配,并且不考虑主模板。 / p>

在您的示例中,由于您提供的部分特化,如果您尝试使用单个模板参数实例化A,则无论是否使用默认模板参数,都无法匹配主模板,或者两个相同的类型。

当然,解决方案是提供A<T, T>::f()

的定义
template <class T>
void A<T, T>::f() {}

编辑:
在存在部分专业化的情况下,匹配它们的规则由(来自N3797)§14.5.5.1/ 1 [temp.class.spec.match] 给出

  

在需要的上下文中使用类模板时   实例化该类,有必要确定是否   实例化将使用主模板或其中一个生成   部分专业化。这是通过匹配模板来完成的   使用模板的类模板特化的参数   部分特化的参数列表。   
- 如果找到一个匹配的特化,则从该特化生成实例化。   
- 如果找到多个匹配的专业化,则使用偏序规则(14.5.5.2)来确定是否有一个   专业化比其他专业化更专业。 ...   
- 如果未找到匹配项,则从主模板生成实例化。

在您的示例中,第一条规则适用,编译器甚至没有达到第3条规则。

答案 1 :(得分:1)

在类外部定义类模板的成员函数时,您只是为类模板中声明的相应函数定义函数。您没有创建可能与其他参数匹配的新功能模板。在您的示例中:

template <class T, class U = T>
class A {
  public:
    void f(); // This is the declaration of A<T,U>::f()
};

template <class T>
class A<T, T> {
  public:
    void f();  // This is the declaration of A<T,T>::f()
};

template <class T, class U>
void A<T, U>::f() {} // This is the definition of A<T,U>::f()

// There is no definition of A<T,T>::f()

我相信你的想法是编译器会看到你正在调用A<int,int>::f()并查看成员函数定义并查找匹配的函数,但这不是会发生的事情。编译器总是查看类模板以查找要调用的函数,一旦找到匹配项,它就会查找相应的定义。在您的情况下,您正在调用A<int,int>::f(),因此它首先查找与A<int,int>匹配的类定义,并找到您的A<T,T>类模板特化。它看到A<T,T>确实有一个名为f的成员函数与函数调用匹配,这意味着A<T,T>::f()需要实例化。要实例化A<T,T>::f(),编译器会查找A<T,T>::f()的定义,但是找不到它。它只找到A<T,U>::f的定义,它不匹配。用于查找正确函数声明的模板参数匹配不适用。