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::string
和char 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)
.)