如何确定函数专业化的主要模板?

use*_*080 6 c++ templates template-specialization

函数模板专业化的主要模板通常非常直观,但是,我正在寻找正式的规则来理解更令人惊讶的情况.例如:

template <typename T, typename U>
void f(T, U) {}     // (1)

template <typename T>
void f(T, T) {}     // (2)

template <>
void f(int, int) {} // (3); specializes (2), not (1); why?
Run Code Online (Sandbox Code Playgroud)

从理论上讲,(3)也可以是(1)的特化,但实验表明它不是.

Rer*_*ito 8

让我们关注通用模板(1)和(2)的声明.这是两个不同的模板,例如(2)不是(1)的特化.好的,现在我们写专业时:

template <>
void foo(int, int) {}
Run Code Online (Sandbox Code Playgroud)

在推断出要专门化的模板时,编译器将识别两个候选者.然后,它必须选择哪个最合适.这种选择的过程称为"功能模板的部分排序".选择报价:

当相同的函数模板特化匹配多个重载的函数模板时(这通常由模板参数推导产生),执行重载函数模板的部分排序以选择最佳匹配.

让我们调用S匹配模板集.然后,对于每一对(F1,F2)小号,编译器将变换F1通过应用伪类型的其类型(相应的值)(相应的非型)的参数.然后它尝试将它与f2匹配.然后它通过转换f2并尝试将其与f1匹配来执行相同的过程.最后,在完成每一对之后,编译器可以确定哪个候选模板是最专业的.如果未能这样做,则编译失败.

在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:

  • 转换(1)应用于(2):假设foo为T = T1且U = T2.它试图与(2)匹配:扣除失败
  • 变换(2)应用于(1):foo(T1,T1),当应用于(1)时,它解析为T = T1且U = T1.

从这个过程,编译器推断出(2)比(1)更专业,你的专业化为(2).当编译器关注特定调用时,在重载解析期间应用相同的过程.

所有这些程序的一个例子如下(摘自@ Yakk的评论):

template <typename T, typename U>
void f(T, U) { std::cout << "f(1)\n"; }     // f(1)

template <typename T>
void f(T, T) { std::cout << "f(2)\n"; }     // f(2)

template <>
void f(int, int) { std::cout << "f(3)\n"; } // f(3); specializes f(2), not f(1); why?

// Now the same specialization but without any template overload...
template <typename T, typename U>
void g(T, U) { std::cout << "g(1)\n"; }     // g(1)

template <>
void g(int, int) { std::cout << "g(3)\n"; } // g(3); No ambiguity, specializes g(1)
Run Code Online (Sandbox Code Playgroud)

接下来,让我们执行几个调用:

f(1, 1); // Prints f(3)
f<int>(1, 1); // Prints f(3)
f<int, int>(1, 1); // Prints f(1)
g(1, 1); // Prints g(3)

g<int, int>(1, 1); // Prints g(3)
Run Code Online (Sandbox Code Playgroud)

所有这一切都可以在这里看到- 复制自@ Yakk的评论.