我有以下代码:
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>
?
答案 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
的定义,它不匹配。用于查找正确函数声明的模板参数匹配不适用。