2

我已经通过 VS2010 运行了以下代码。

#include <iostream>

template<class T> // (a) a base template 
void f( T )
{    std::cout << "(a)" << std::endll;}

template<class T> // (b) a second base template, overloads (a) 
void f( T* )     //     (function templates can't be partially 
{    std::cout << "(b)" << std::endll;}

template<>        // (c) explicit specialization of (b) 
void f<>(int*)
{    std::cout << "(c)" << std::endll;}

int main(int argc, char* argv[])
{
    int *p = new int(10); 
    f( p ); // '(c)'

    return 0;
}

////////////////

#include <iostream>

template<class T> // (a) same old base template as before 
void f( T )
{    std::cout << "(a)" << std::endll;}

template<>        // (c) explicit specialization, this time of (a)
void f<>(int*)
{    std::cout << "(c)" << std::endll;}

template<class T> // (b) a second base template, overloads (a) 
void f( T* )
{    std::cout << "(b)" << std::endll;}

int main(int argc, char* argv[])
{
    int *p = new int(10); 
    f( p ); // '(b)'

    return 0;
}

输出结果为(c)。但是,如果我将 (c) 代码块移动到 (b) 前面,则输出结果为(b). 我在这里阅读了相关文章http://www.gotw.ca/publications/mill17.htm。还是会糊涂。

为什么代码的顺序在案例中很重要?

4

2 回答 2

2

我认为您已经掌握了问题中的大部分信息。问题是有两个基本模板是重载的并且是不相关的。

如果仅在声明它们中的第一个时执行特化,则编译器将认为这是第一个模板的特化T == int*。现在,在声明了两个模板之后,当您执行调用时,编译器将只查看基本模板,并确定第二个模板更适合表达式。第二个模板没有特化,因此使用基本模板定义。

让我强调一下:模板专业化只有在选择了它们的基本模板后才会发挥作用。它们不会影响编译器将选择的基本模板。

如果将特化移动到声明第二个模板之后T == int,编译器会将该特化与带有. 在这种情况下,当编译器选择第二个模板作为main专业化调用的最佳匹配时,您将获得专业化行为。

于 2012-08-16T15:07:51.243 回答
1

正如文章中所解释的,当您移动专业化时,它会更改正在专业化的功能。当您将专业化放在 (b) 之前时,它会专门化 (a)。

template<>        // (c) explicit specialization of (a) <-- here
void f<>(int*)
{    cout << "(c)" << endl;}

在这两种情况下,当您调用 时f(p),编译器首先会查看 (a) 和 (b),并确定哪个重载更合适。正如您列出的文章所解释的那样,专业化不参与重载解决,因此在这两个示例中,它都选择了 (b)。此时,它会寻找 (b) 的任何特化。

在第一种情况下,因为你用 (c) 专门化了 (b),所以它执行 (c)。在第二种情况下,由于您没有专门化 (b),它执行 (b)。

编辑:防止订单重要的最简单方法是在提供专业化之前先声明(a)和(b)。在这种情况下,编译器能够推断出您的意图。见http://ideone.com/qj2JC

于 2012-08-16T15:09:22.177 回答