什么是非演绎的语境?
What is a nondeduced context?
我绊倒了"为什么模板参数演绎不工作在这里?,答案可以总结为"这是一个非推断的语境"。
具体来说,第一个说它是这样的事情,然后重定向到标准的"细节",而第二个引用标准,这至少可以说是神秘的。
谁能给我这样的凡人解释一下,什么是非演绎上下文,它什么时候发生,为什么发生?
演绎是指根据给定实参确定模板形参类型的过程。它适用于函数模板、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)
时遇到过这样的演绎问题)
注意:std::type_identity
从c++ 20开始在标准库中可用
- 模板模板参数的演绎指南
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 提升精神 QI:在元组上自动规则演绎,在替代函数中带有序列
- 类模板专用化演绎是否应该考虑演绎指南参数初始化?
- 演绎指南中的参考文献和值之间的差异
- 为什么 std::array 的演绎指南不允许不同的类型?
- 是否有可能通过演绎指南实现整个 std::make_tuple 功能?
- 矩阵的演绎指南
- C++17类模板演绎常性
- C++17模板演绎指南不用于空参数集?
- 如何使用模板化构造函数定义演绎指南?
- 为什么"packaged_task"没有演绎指南?
- 类型演绎 C++ 标准和自动
- C++ 1Z 错误:错误:演绎指南中声明中的显式限定
- λ类型演绎失败
- SFINAE使用演绎,但用替换失败
- 演绎指南和具有可变参数模板构造函数的可变参数类模板 - 参数包长度不匹配
- decltype(auto) 类型演绎:返回 x 与返回 (x)
- 可变参数模板构造函数的演绎指南失败
- 什么是非演绎的语境?