什么是非弱化背景?

Sho*_*hoe 57 c++ templates template-argument-deduction argument-deduction

我最近接触过这个问题,答案可以概括为"这是一个非受限的背景".

具体来说,第一个说它是这样的东西,然后重定向到"细节"的标准,而第二个引用标准,这至少可以说是神秘的.

有人可以向凡人解释,比如我自己,什么是非受限的背景,什么时候发生,为什么会发生?

Ker*_* SB 88

扣除是指从给定参数确定模板参数类型的过程.它适用于函数模板,auto以及一些其他情况(例如,部分特化).例如,考虑:

template <typename T> void f(std::vector<T>);
Run Code Online (Sandbox Code Playgroud)

现在,如果你说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);
Run Code Online (Sandbox Code Playgroud)

在此函数模板中,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>  { };
Run Code Online (Sandbox Code Playgroud)

如果你打电话g(double{})有两个可能的答案T,如果你打电话g(int{})没有答案.通常,类模板参数和类成员之间没有关系,因此您不能执行任何合理的参数推断.


有时,明确地抑制参数推断是有用的.这是例如的情况std::forward.另一个例子是,当你从转换Foo<U>Foo<T>,比方说,或其他转换(思std::stringchar const *).现在假设你有一个自由函数:

template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
Run Code Online (Sandbox Code Playgroud)

如果你打电话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);
}
Run Code Online (Sandbox Code Playgroud)

(你可能已经经历过类似的演绎问题std::min(1U, 2L).)

  • 关键在于:类型`T`和模板类`Foo <T>`之间存在一对一的对应关系,因此您可以从后者中推断出前者.但是类型`T`和任意成员`Foo <T> :: X`之间没有*对应关系. (4认同)