In 他的回答 https://stackoverflow.com/a/22259156/420683 to 这个问题 https://stackoverflow.com/q/22258054/420683以及评论区,约翰内斯·绍布 https://stackoverflow.com/users/34509/johannes-schaub-litb说当尝试对需要的参数多于已传递的参数的函数模板进行模板类型推导时,出现“匹配错误”:
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
for T == int
,替换会产生不在直接上下文中的无效类型foo
。这会导致一个硬错误(这就是相关问题 https://stackoverflow.com/q/22258054/420683是关于。)
然而,当让foo
推导出它的模板参数,g++ 和 clang++ 一致认为不会发生实例化。作为约翰内斯·绍布解释说 https://stackoverflow.com/questions/22258054/c-inconsistency-between-gcc-and-clang#comment33810551_22259156,这是因为存在“匹配错误”。
问题:什么是“匹配错误”,标准中在何处以及如何指定?
替代问题:为什么两者之间存在差异foo(42)
and foo<int>(42)
对于g++?
到目前为止我发现/尝试过的:
[over.match.funcs]/7 和 [temp.over] 似乎描述了函数模板的重载解析细节。后者似乎要求用模板参数替换foo
.
有趣的是,[over.match.funcs]/7 触发了[temp.over]中描述的过程before检查函数模板的可行性(专业化)。
类似地,类型推导不会考虑默认函数参数(除了使它们成为非推导上下文)。据我所知,这似乎与生存能力无关。
另一个可能重要的方面是如何指定类型推导。它作用于单个函数参数,但我看不出包含/依赖于模板参数的参数类型之间有什么区别(例如T const&
)和那些不是(比如int
).
然而,g++ 在显式指定模板参数(硬错误)和让它们被推导(推导失败/SFINAE)之间存在差异。为什么?