解析c ++模板规范和重载

ls.*_*ls. 10 c++ templates template-specialization

我已经阅读了为什么不专业化功能模板,经过一些实验,我发现了一件有趣的事情.这里去main.cxx:

// main.cxx
#include <iostream>

// Declarations
/*
template<class T>
void foo(T);

template<>
void foo(int*);

template<class T>
void foo(T*);
*/

// Definition and specification
template<class T>
void foo(T x)
{
    std::cout << "T version." << std::endl;
}

template<>
void foo(int *i)
{
    std::cout << "int* version." << std::endl;
}

template<class T>
void foo(T *x)
{
    std::cout << "T* version" << std::endl;
}

int main(int argc, char** argv)
{
  int *p;
  foo(p);
}
Run Code Online (Sandbox Code Playgroud)

有趣的是:如果我留下声明部分进行评论,那么行为就像文章所说的那样,即如果int*version的定义在其定义之前,副本和经文之前,将使用T*版本.但是,如果取消注释声明块,则无论我在定义或声明中使用哪个顺序,都只会调用int*version.我的问题是这个声明如何影响决议?

有任何想法吗?我在x86_64-redhat-linux上使用g ++ 4.2.2

编辑:看到AProgrammer的答案后简化这个问题

APr*_*mer 10

分发源成三个文件搞乱事项:预处理使一个编译单元和行为只是取决于CU的内容,而不是在它被多少个文件分发.

在这种情况下,我认为你很惊讶

#include <iostream>

template<class T> void foo(T); // A
template<> void foo(int*); // 1
template<class T> void foo(T*); // B

template<class T> void foo(T x)
{ std::cout << "T version." << std::endl; }

template<> void foo(int *i) // 2
{ std::cout << "int* version." << std::endl; }

template<class T> void foo(T *x)
{ std::cout << "T* version" << std::endl; }

int main(int argc, char** argv) {
  int *p;
  foo(p);
}
Run Code Online (Sandbox Code Playgroud)

你得到int* version.这是预期的行为.虽然(1)确实声明了专业化template <typename T> void foo(T),但(2)不是该专业化的定义.(2)定义并声明template<class T> void foo(T*);其中的特化,然后调用main().如果您在声明和定义的任何内容中给出三个定义之前的三个声明,就会发生这种情况.定义(2)将始终看到声明template<class T> void foo(T*);,因此是它的专业化.

当声明或定义函数模板的特化时,它可以是几个函数模板的特化(比如这里(2)可以是两个重载A和B的特化,它们只需要声明),它就是一个专业化的"更专业化"的一个.您可以在标准17.5.5.2节中看到"更专业"的精确定义,但很容易看出B对于(2)来说是比A更好的匹配,因此(2)是(B)的特化.(1)宣布(A)的专业化,因为当宣布(1)时,(B)尚未被看见.如果你想在(B)之后给出(1)的定义,你必须写

template <> void foo<int*>(int*) // definition for (1)
{ std::cout << "foo<int*>(int*)\n"; }
Run Code Online (Sandbox Code Playgroud)

在定义(2)时你也可以是明确的:

template<> void foo<int>(int *i) // 2 alternate
{ std::cout << "int* version." << std::endl; }
Run Code Online (Sandbox Code Playgroud)

(但显然在同一个CU中给出(2)和这个替代版本会给你一个错误).

调用函数时也可以显式:

foo(p); // call (2)
foo<int>(p); // call (2)
foo<int*>(p); // call (1)
Run Code Online (Sandbox Code Playgroud)