Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么通用模板方法定义没有';与模板类专门化不匹配?_C++_Templates_C++11 - Fatal编程技术网

C++ 为什么通用模板方法定义没有';与模板类专门化不匹配?

C++ 为什么通用模板方法定义没有';与模板类专门化不匹配?,c++,templates,c++11,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<

我有以下代码:

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;
}
模板
甲级{
公众:
无效f();
};
模板
甲级{
公众:
void f();//未更改的方法。
//有些差异。
};
模板
void A::f(){}
int main(){
A A;
a、 f();
返回0;
}
clang++-std=c++11 test.cc
给了我一个错误:
对'A::f()'的引用未定义。


为什么提供的方法
f()
的定义不适用于类
A

主要类模板
模板类A
和部分专业化
模板类A
是两个不同的模板定义。定义它们之后,无论何时引用类模板名称
A
,都将始终考虑主模板和所有部分专门化

无论何时使用单个模板参数或两个相同类型的参数实例化
A
,它都会更好地匹配您提供的专门化,并且不考虑主模板

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

当然,解决方案是为
A::f()

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

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


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

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

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()
模板
甲级{
公众:
void f();//这是A::f()的声明
};
模板
甲级{
公众:
void f();//这是A::f()的声明
};
模板
void A::f(){}//这是A::f()的定义
//没有A::f()的定义

我相信您的想法是,编译器将看到您正在调用
A::f()
,并将查看成员函数定义并找到一个匹配的,但实际情况并非如此。编译器总是通过类模板查找要调用的函数,一旦找到匹配项,就会查找相应的定义。在您的例子中,您正在调用
A::f()
,因此它首先查找与
A
匹配的类定义,然后找到您的
A
类模板专用化。它看到
A
确实有一个名为
f
的成员函数,它与您的函数调用相匹配,这意味着
A::f()
需要实例化。要实例化
A::f()
,编译器会查找
A::f()
的定义,但找不到它。它只找到
A::f
的定义,该定义不匹配。用于查找正确函数声明的模板参数匹配不适用。

谢谢您的回答,但如果您提供编译器不考虑我的定义的更多详细信息,那就太好了-据我所知,该定义是一个不同的模板,应该在两个类模板上匹配。我错过了什么?@Abyses.7我已经更新了答案。简短的回答是因为语言规则说只匹配部分专门化,而不匹配主要的。我不明白,但我真的想:如果类模板实例化在
template void A::f(){}
-行中是必需的,那么它应该匹配
void A::f(){}
,即类模板的专门化,应该没有问题。也许吧,我们可以聊一聊吗?@Abysis.7在聊天中我再也解释不清楚了。我上面引用的第一个要点非常明确,在您的案例中不可能匹配主模板。如果您有一个只关心第一个模板参数类型的成员函数,并且您希望主专用化和部分专用化共享此函数的实现,则可以选择创建(
friend
maybe)两个类模板都可以调用的非成员函数模板。A和A有什么区别?您可能可以避免类的专门化(使用enable_if,SFINAE…。@ysdx的区别在于本地类的声明以及它在某些方法中的用法。
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()