【问题标题】:What is a nondeduced context?什么是非演绎上下文?
【发布时间】:2019-11-04 10:24:16
【问题描述】:

我绊倒了“Why is the template argument deduction not working here?”最近,答案可以总结为“这是一个不可推导的上下文”。

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

有人可以向像我这样的凡人解释一下,什么是非演绎语境是什么时候发生,为什么会发生?

【问题讨论】:

标签: c++ templates template-argument-deduction


【解决方案1】:

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

template <typename T> void f(std::vector<T>);

现在如果你说f(x),你声明std::vector&lt;int&gt; x;的地方,那么T就是推导作为int,您将获得专业化f&lt;int&gt;

为了推导工作,要推导的模板参数类型必须出现在可推导的上下文中。在这个例子中,f 的函数参数就是这样一个可推导的上下文。也就是说,函数调用表达式中的参数允许我们确定模板参数 T 应该是什么以使调用表达式有效。

然而,也有-推导上下文,其中无法推导。典型示例是“出现在:: 左侧的模板参数:

template <typename> struct Foo;

template <typename T> void g(typename Foo<T>::type);

在该函数模板中,函数参数列表中的T处于非推导上下文中。因此,您不能说 g(x) 并推断出 T。这样做的原因是任意类型和之间没有“向后对应”成员Foo&lt;T&gt;::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&lt;U&gt;Foo&lt;T&gt; 的转换,或者其他转换(想想 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 指定的类型的嵌套名称说明符。”)?
  • 其实,现在细读起来,我觉得恰恰相反。
  • @Jeffrey:也许像template &lt;std::size_t&gt; struct Bar; template &lt;typename T&gt; void(Bar&lt;sizeof(T)&gt;);
  • 重点是:类型T和模板类Foo&lt;T&gt;之间存在一一对应关系,所以你可以从后者推导出前者。但是还有类型T和任意成员Foo&lt;T&gt;::X之间的对应关系。
  • 我觉得你也可以回答this
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
相关资源
最近更新 更多