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)的特化,但实验表明它不是.
让我们关注通用模板(1)和(2)的声明.这是两个不同的模板,例如(2)不是(1)的特化.好的,现在我们写专业时:
template <>
void foo(int, int) {}
Run Code Online (Sandbox Code Playgroud)
在推断出要专门化的模板时,编译器将识别两个候选者.然后,它必须选择哪个最合适.这种选择的过程称为"功能模板的部分排序".选择报价:
当相同的函数模板特化匹配多个重载的函数模板时(这通常由模板参数推导产生),执行重载函数模板的部分排序以选择最佳匹配.
让我们调用S匹配模板集.然后,对于每一对(F1,F2)在小号,编译器将变换F1通过应用伪类型的其类型(相应的值)(相应的非型)的参数.然后它尝试将它与f2匹配.然后它通过转换f2并尝试将其与f1匹配来执行相同的过程.最后,在完成每一对之后,编译器可以确定哪个候选模板是最专业的.如果未能这样做,则编译失败.
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
从这个过程,编译器推断出(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的评论.