10

我已经阅读了Why Not Specialize Function Templates,经过一些实验,我发现了一件有趣的事情。这是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);
}

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

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

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

4

1 回答 1

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);
}

你明白了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 中看到“更专业化”的精确定义,但很容易看出,对于 (2),B 比 A 更匹配,因此 (2) 是 (B) 的专业化. (1) 声明 (A) 的特化,因为当声明 (1) 时,还没有看到 (B)。如果你想在看到 (B) 之后给出 (1) 的定义,你必须写

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

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

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

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

调用函数时也可以显式:

foo(p); // call (2)
foo<int>(p); // call (2)
foo<int*>(p); // call (1)
于 2011-06-09T16:15:11.590 回答