什么是非诱骗情境?
我最近接触到这个问题 ,可以归纳为“这是一个没有被诱惑的背景”。
具体来说,第一个说这是一个事情,然后redirect到“细节”的标准,而第二个引用的标准,这是至less可以说是神秘的。
难道有人能像我这样向凡人解释什么是一个非诱惑的情境 ,什么时候发生,为什么会发生?
这非常简单: 演绎是指从给定参数确定模板参数types的过程。 它适用于function模板, auto
和其他一些情况(如部分专业化)。 例如,考虑:
template <typename T> void f(std::vector<T>);
现在如果你说f(x)
,你声明std::vector<int> x;
,则T
被推导为int
,并且得到专门化的f<int>
。
为了使演绎有效,要推导的模板参数types必须出现在可推论的上下文中。 在这个例子中, f
的函数参数就是这样一个可推论的上下文。 也就是说,函数调用expression式中的参数允许我们确定模板参数T
应该是什么,以使调用expression式有效。
但是,也有一些没有被扣减的情况,不可能有任何扣除。 规范示例是“显示在::
的左侧的模板参数:
template <typename> struct Foo; template <typename T> void g(typename Foo<T>::type);
在此函数模板中,函数参数列表中的T
处于非推导的上下文中。 所以你不能说g(x)
并推导出T
原因是任意types和成员 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 *
)。 现在假设你有一个免费的function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
如果调用binary_function(t, u)
,则扣除可能不明确,从而导致失败。 但只推导一个参数而不推导另一个参数是合理的,因此允许隐式转换。 现在需要一个明确的非推断的上下文,例如像这样:
template <typename T> bool binary_function(Foo<T> lhs, typename std::common_type<Foo<T>>::type rhs) { return binary_function(lhs, rhs); }
(你可能遇到过像std::min(1U, 2L)
这样的推理问题。)