什么是非诱骗情境?

我最近接触到这个问题 ,可以归纳为“这是一个没有被诱惑的背景”。

具体来说,第一个说这是一个事情,然后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::stringchar 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)这样的推理问题。)