扣除指的是根据给定参数确定模板参数类型的过程。它适用于函数模板,auto,以及一些其他情况(例如偏特化)。例如,考虑:
template <typename T> void f(std::vector<T>);
现在如果你说f(x),你声明std::vector<int> x;的地方,那么T就是推导作为int,您将获得专业化f<int>。
为了推导工作,要推导的模板参数类型必须出现在可推导的上下文中。在这个例子中,f 的函数参数就是这样一个可推导的上下文。也就是说,函数调用表达式中的参数允许我们确定模板参数 T 应该是什么以使调用表达式有效。
然而,也有非-推导上下文,其中无法推导。典型示例是“出现在:: 左侧的模板参数:
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
在该函数模板中,函数参数列表中的T处于非推导上下文中。因此,您不能说 g(x) 并推断出 T。这样做的原因是任意类型和之间没有“向后对应”成员Foo<T>::type。例如,您可以拥有以下专业:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
如果您拨打g(double{}),T 有两个可能的答案,如果您拨打g(int{}),则没有答案。通常,类模板参数和类成员之间没有任何关系,因此您无法执行任何合理的参数推导。
有时明确禁止参数推导是有用的。例如std::forward就是这种情况。另一个例子是当你有从 Foo<U> 到 Foo<T> 的转换,或者其他转换(想想 std::string 和 char const *)。现在假设你有一个自由函数:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
如果你调用binary_function(t, u),那么推导可能会产生歧义,从而失败。但只推导出一个论点是合理的,并且不是推导另一个,从而允许隐式转换。现在需要一个明确的非推导上下文,例如:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(您可能遇到过类似 std::min(1U, 2L) 的推导问题。)