his answerthis 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 ,这是因为存在“匹配错误”。

问题:什么是“匹配错误”,它在标准中的何处以及如何指定?

替代问题:为什么 g++ 的 foo(42)foo<int>(42) 之间存在差异?

到目前为止我发现/尝试过的:

[over.match.funcs]/7 和 [temp.over] 似乎描述了函数模板的重载解析细节。后者似乎要求替换 foo 的模板参数。

有趣的是,[over.match.funcs]/7 在检查函数模板的可行性(特化)之前触发了 [temp.over] 中描述的过程。
类似地,类型推导不考虑默认函数参数(除了使它们成为非推导上下文)。据我所知,它似乎与生存能力无关。

另一个可能重要的方面是如何指定类型推导。它作用于单个函数参数,但我看不出包含/依赖于模板参数的参数类型(如 T const& )和不依赖模板参数的参数类型(如 int )之间的区别在哪里。

然而,g++ 在明确指定模板参数(硬错误)和让它们被推导(推导失败/SFINAE)之间有所不同。为什么?

最佳答案

我总结的是14.8.2.1p1中描述的过程



在我们的例子中,我们有 P (T, int) 和 A,我们有 (int) 。对于第一对 P/A,即 Tint ,我们可以将 Tint 匹配(通过 14.8.2.5 中描述的过程)。但是对于第二个“对”,我们有 int 但没有对应的。因此,不能对该“对”进行扣除。

因此,在 14.8.2.5p2 中,“如果不能对任何 P/A 对进行类型推导,...,模板
论证推导失败。”。

然后,您将永远不会将模板参数替换为函数模板。

这可能都可以在标准 (IMO) 中更准确地描述,但我相信这是实现事物以匹配 Clang 和 GCC 的实际行为的方式,并且这似乎是对 Standardese 的合理解释。

关于c++ - 非可行函数模板的类型推导,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22300620/

10-11 22:35
查看更多