在his answer至 this question和评论部分,Johannes Schaub说当尝试对需要比已传递的参数更多的参数的函数模板进行模板类型推导时出现“匹配错误”:
template<class T>
void foo(T, int);
foo(42); // the template specialization foo<int>(int, int) is not viable
在另一个问题的上下文中,相关的是函数模板的类型推导是否成功(并且发生替换):
template<class T>
struct has_no_nested_type {};
// I think you need some specialization for which the following class template
// `non_immediate_context` can be instantiated, otherwise the program is
// ill-formed, NDR
template<>
struct has_no_nested_type<double>
{ using type = double; };
// make the error appear NOT in the immediate context
template<class T>
struct non_immediate_context
{
using type = typename has_no_nested_type<T>::type;
};
template<class T>
typename non_immediate_context<T>::type
foo(T, int) { return {}; }
template<class T>
bool foo(T) { return {}; }
int main()
{
foo(42); // well-formed? clang++3.5 and g++4.8.2 accept it
foo<int>(42); // well-formed? clang++3.5 accepts it, but not g++4.8.2
}
实例化第一个函数模板时foo
对于 T == int
, 替换产生的无效类型不在 foo
的直接上下文中.这会导致硬错误(这就是 the related question 的意思。)
然而,当让foo
推导它的模板参数,g++ 和 clang++ 同意没有实例化发生。作为Johannes Schaub explains ,这是因为存在“匹配错误”。
问题:什么是“匹配错误”,它在标准中的何处以及如何规定?
替代问题:为什么 foo(42)
之间存在差异?和 foo<int>(42)
对于 g++?
到目前为止我发现/尝试过的:
[over.match.funcs]/7 和 [temp.over] 似乎描述了函数模板的重载解析细节。后者似乎要求用模板参数替换 foo
.
有趣的是,[over.match.funcs]/7 触发了 [temp.over] before 中描述的过程,检查函数模板的可行性(特化)。 类似地,类型推导不考虑默认函数参数(除了使它们成为非推导上下文)。据我所知,它似乎并不关心生存能力。
另一个可能重要的方面是如何指定类型推导。它作用于单个函数参数,但我看不到包含/依赖于模板参数(如 T const&
)和不包含/依赖于模板参数(如 int
)的参数类型之间的区别。
然而,g++ 在显式指定模板参数(硬错误)和推导它们(推导失败/SFINAE)之间做出了区分。为什么?
最佳答案
我总结的是14.8.2.1p1描述的流程
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
在我们的例子中,对于 P,我们有 (T, int)
,对于 A,我们有 (int)
。对于第一对 P/A,即 T
对 int
,我们可以将 T
匹配到 int
(通过 14.8.2.5 中描述的过程)。但是对于第二个“对”,我们有 int
但没有对应物。因此不能对这个“对”进行扣除。
因此,根据 14.8.2.5p2,“如果无法对任何 P/A 对进行类型推导,...,模板 参数推导失败。”。
这样一来,您就再也不会将模板参数替换到函数模板中了。
这可能都可以在标准 (IMO) 中得到更准确的描述,但我相信这是人们可以如何实现与 Clang 和 GCC 的实际行为相匹配的东西,这似乎是对标准的合理解释。
关于c++ - 不可行函数模板的类型推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22300620/