为什么实施订单在“为什么不专门化功能模板”中很重要

时间:2012-08-16 14:57:49

标签: c++

我已通过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)。 但是,如果我在(b)前移动(c)代码块,则输出结果为(b)。 我在这里阅读了相关文章http://www.gotw.ca/publications/mill17.htm。仍然感到困惑。

为什么代码的顺序在这种情况下很重要?

2 个答案:

答案 0 :(得分:2)

我认为你已经在问题中提供了大部分信息。问题是有两个基本模板是重载,否则无关。

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

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

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

答案 1 :(得分:1)

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

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

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

在第一种情况下,由于你有专门的(b)和(c),它执行(c)。在第二种情况下,由于你没有专门(b​​),它执行(b)。

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