什么是非推论上下文?


68

我最近偶然发现“为什么模板参数推导在这里不起作用? ”,答案可以总结为“这是一个非推论的上下文”。

具体来说,第一个引用这样的东西,然后重定向到“详细信息”的标准,而第二个引用该标准,至少可以这样说。

有人能像我一样向凡人解释一个非推论的上下文是什么,它何时发生,为什么发生?


Answers:


98

推论是指根据给定参数确定模板参数类型的过程。它适用于功能模板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::stringchar 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)。)


因此,您引用的是标准描述的第二种情况(“一种类型是模板ID,其中一个或多个模板参数是引用模板参数的表达式。”),对吗?如果是这样,您可以举一个第一个示例(“使用限定ID指定的类型的嵌套名称说明符”)吗?
2014年

1
实际上,既然我仔细阅读了,我认为是相反的。
2014年

@Jefffrey:也许是这样的template <std::size_t> struct Bar; template <typename T> void(Bar<sizeof(T)>);
Kerrek SB 2014年

4
关键在于:类型T和模板类之间存在一一对应的关系Foo<T>,因此您可以从后者中推导出前者。但是类型和任意成员之间没有对应关系。TFoo<T>::X
Kerrek SB 2014年

我觉得您也可以回答这个问题
Baum mit Augen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.