如何确定函数特化的主模板?
How to determine the primary template of a function 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?
理论上,(3) 也可以是 (1) 的特化,但实验表明它不是。
让我们关注通用模板(1) 和(2) 的声明。
这是两个不同的模板,例如(2) 不是 (1) 的特化。好的,现在我们写专业化:
template <>
void foo(int, int) {}
在推断要专门化哪个模板时,编译器将确定两个候选者。然后,它必须选择最适合。这种选择的过程称为"partial ordering of function templates"。选择的报价:
When the same function template specialization matches more than one overloaded function template (this often results from template argument deduction), partial ordering of overloaded function templates is performed to select the best match.
我们称S匹配模板集。然后,对于 S 中的每一对 (f1, f2),编译器将通过应用变换 f1其类型(resp。非类型)参数的虚拟类型(resp。值)。然后它尝试将它与 f2 进行匹配。然后它通过转换 f2 并尝试将其与 f1 匹配来执行相同的过程。最后,在遍历每一对之后,编译器可以确定哪个模板候选是最专业的。如果它不这样做,则编译失败。
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
- 应用于 (2) 的转换 (1):说 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)
接下来,让我们执行几个调用:
f(1, 1); // Prints f(3)
f<int>(1, 1); // Prints f(3)
f<int, int>(1, 1); // Prints f(1)
f(0.1, 0.2); // Prints f(2)
g(1, 1); // Prints g(3)
g<int, int>(1, 1); // Prints g(3)
这一切都可以在行动中看到here - copied from @Yakk's comment。
主题似乎是模板'partial ordering'。可以在此处找到一个示例:
what's the partial ordering procedure in template deduction
函数模板特化的主模板通常是非常直观的,但是,我正在寻找正式规则以了解更令人惊讶的情况。例如:
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?
理论上,(3) 也可以是 (1) 的特化,但实验表明它不是。
让我们关注通用模板(1) 和(2) 的声明。 这是两个不同的模板,例如(2) 不是 (1) 的特化。好的,现在我们写专业化:
template <>
void foo(int, int) {}
在推断要专门化哪个模板时,编译器将确定两个候选者。然后,它必须选择最适合。这种选择的过程称为"partial ordering of function templates"。选择的报价:
When the same function template specialization matches more than one overloaded function template (this often results from template argument deduction), partial ordering of overloaded function templates is performed to select the best match.
我们称S匹配模板集。然后,对于 S 中的每一对 (f1, f2),编译器将通过应用变换 f1其类型(resp。非类型)参数的虚拟类型(resp。值)。然后它尝试将它与 f2 进行匹配。然后它通过转换 f2 并尝试将其与 f1 匹配来执行相同的过程。最后,在遍历每一对之后,编译器可以确定哪个模板候选是最专业的。如果它不这样做,则编译失败。
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
- 应用于 (2) 的转换 (1):说 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)
接下来,让我们执行几个调用:
f(1, 1); // Prints f(3)
f<int>(1, 1); // Prints f(3)
f<int, int>(1, 1); // Prints f(1)
f(0.1, 0.2); // Prints f(2)
g(1, 1); // Prints g(3)
g<int, int>(1, 1); // Prints g(3)
这一切都可以在行动中看到here - copied from @Yakk's comment。
主题似乎是模板'partial ordering'。可以在此处找到一个示例: what's the partial ordering procedure in template deduction