【问题标题】:Correct way to use decltype as trailing return type使用 decltype 作为尾随返回类型的正确方法
【发布时间】:2011-04-27 09:56:45
【问题描述】:

我经常看到这种形式的例子:

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(std::forward<T>(t) + std::forward<U>(u))
{
    return std::forward<T>(t) + std::forward<U>(u);
}  

但我敢说这是更好更正确的方式:

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(t + u)//no forwarding here
{
    return std::forward<T>(t) + std::forward<U>(u);
}

为什么?首先,这个例子中的 decltype 只需要推断返回类型,所以 (t + u) 是返回类型而不是 (std::forward(t) + std::forward(u)),第二个代码由两个 ver 生成相同,第三个 decltype(u + t) 更直接,准确地表达了程序员的意图,而不带出实现的“胆量”。

你对这个问题有什么看法?

【问题讨论】:

    标签: c++ templates c++11 decltype perfect-forwarding


    【解决方案1】:

    第一个版本更正确,因为它完全匹配函数体将要返回的内容。正如已经指出的那样,根本无法保证

    decltype(std::forward<T>(t) + std::forward<U>(u))
    

    将与

    的类型相同
    decltype(t + u)
    

    可以说,这是一个非常极端的情况,但“正确”的方法是使用 std::forward。

    【讨论】:

      【解决方案2】:

      一般来说,我想不出一个明智的用例会有所不同,但我想你会发现一些情况,操作对右值引用和右值有不同的实现,并且语言规则没有规定不同重载的返回类型必须相同(即使常识会规定)。

      因此,在一般情况下,不会有任何差异,而在存在差异的情况下,那些情况需要格外小心和注意,以应对比模板本身更糟糕的问题......

      // sick corner case:
      struct type {};
      int operator+( type&& lhs, type&& rhs );
      double operator+( type const & lhs, type const & rhs );
      

      我可以考虑您希望为右值引用提供不同重载的情况(考虑提供operator+ 作为连接的列表的某些实现,然后右值引用的重载可以避免通过仅仅修改来复制的成本使用指针并将参数列表留空),但如果结果的类型取决于参数的 l/rvalue-ness,那将完全令人困惑。

      【讨论】:

      • 我使用 decltype 的次数越多,我就越相信它应该作用于类型而不是对象。因为更自然地想到添加两种类型而不是这些类型的两个对象的结果是什么。
      • @我们无能为力:我不太同意,使用对象而不是类型有一个明显的优势:编译器将对参数执行任何所需的转换:@987654323对于算术类型,@ 将转换为 TU 中的较大者。 template &lt;typename T&gt; auto foo( T x ) -&gt; decltype( foo_(x) ) { return foo_(x); } 将执行从实际Tfoo_ 可用的最佳 重载可能需要的任何隐式转换...
      • 我猜你也可以认为decltype( foo( int ) ) 可以在语法中使用,但这会创建id( type ) 的第一个不完美匹配的情况(在所有其他用途中,有不能从 int) 转换,并且可能会导致混淆。你在说什么foo?我只有foo(doble)foo(string)
      【解决方案3】:

      decltype(t + u) 中,变量tu 已经不再是右值引用,它们将被视为简单的左值引用,因此您需要额外的std::forward。 (至少,我是这么理解的。不过可能是错的。)

      【讨论】:

      • 但这只是为了推断返回类型,没有别的,你不用对 decltype 中的那些变量做任何事情。
      • @There:这可能仍然很重要,因为对于右值引用,operator+ 可能存在特殊重载。
      猜你喜欢
      • 2019-01-26
      • 2023-03-04
      • 2011-11-07
      • 2017-08-02
      • 2017-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多