【问题标题】:Advantages of arrow syntax in function declaration函数声明中箭头语法的优点
【发布时间】:2020-10-19 17:10:44
【问题描述】:

使用有什么好处

template <typename L, typename R> 
auto getsum(L l, R r) -> decltype(l + r) {return l + r;}

结束

 template <typename L, typename R>
 auto getsum(L l, R r) {return l +  r;}

模板实例化的时候不是编译成合适的类型了吗?

【问题讨论】:

    标签: c++ templates trailing-return-type return-type-deduction


    【解决方案1】:

    使用[尾随返回类型语法]有什么好处?

    一个可能的优势:尾随返回类型对 SFINAE 友好。

    只有在lr 之间存在加号运算符时,才会启用具有尾随返回类型 (-&gt; decltype( l + r )) 的 getsum() 函数。

    如果您使用几个不支持总和的参数调用它(例如,几个 std::vector's),您会得到一个不是错误的替换失败 (SFINAE)。

    所以可以调用另一个getsum()函数。

    以下是一个完整的编译示例,其中“做一些不同的事情”版本是从 getsum(a, b) 调用的

    #include <vector>
    
    template <typename ... Ts>
    auto getsum (Ts...)
     { /* do something different */ }
    
    template <typename L, typename R> 
    auto getsum (L l, R r) -> decltype( l + r )
     { return l + r; }
    
    int main ()
     {
       std::vector<int> a, b;
    
       getsum(a, b);
     }
    

    但是如果你去掉尾随的返回类型

    template <typename L, typename R> 
    auto getsum (L l, R r) // <<--- no more tailing return type!!!
     { return l + r; }
    

    代码不再编译,因为您没有替换失败,而是出现硬错误。

    【讨论】:

      【解决方案2】:

      一个优势显然是更短的代码。

      但也有缺点:除了只能从 C++14 开始自动推导返回类型之外,还有无法推导返回类型的情况。

      假设函数的复杂度略有增加:

      template <typename L, typename R>
      auto getsum(L l, R r) {
          if (l < 0)
              return 0;
          return l + r;
      }
      

      现在无法编译:

      int main() {
          auto s = getsum(1L, 2); // error: inconsistent deduction for auto return type: 'int' and then 'long int'
      }
      

      我们通过显式指定返回类型来解决这个问题(例如,使用尾随返回类型语法):

      auto getsum(L l, R r) -> decltype(l + r) {
          if (l < 0)
              return 0;
          return l + r;
      }
      
      int main() {
          auto s = getsum(1L, 2);  // OK
      }
      

      【讨论】:

      • 但是你可以说decltype(l+r) getsum(L l, R r)而不使用箭头符号。
      • @einpoklum,不,你不能,因为此时没有声明 l 和 r。这就是它尾随的原因,您在声明参数之后拥有它。
      • @MikaelH - decltype( std::declval&lt;L&gt;() + std::declval&lt;R&gt;() ) getsum (L l, R r) 怎么样?
      • @MikaelH:嗯,你是对的,但是 - max66 说的。尽管如此,它变得更加麻烦。如果你假设默认构造,你可以做decltype(L() + R())
      • @max66,当然,但我很确定在这种情况下我更喜欢auto getsum(L l, R r) -&gt; decltype(l+r)
      【解决方案3】:

      自 C++14 以来,第二个只是第一个的更简单版本。 在 C++14 之前,您可以将函数名称与 auto 对齐(所以这是关于 codestyle)。

      【讨论】:

      • 不完全正确。存在编译器无法推断返回类型的情况
      • @idclev463035818,例如?
      • 例如当你有多个返回不同类型的返回时(但可以转换为返回类型)
      • @idclev463035818,如果每个人都相互转换,为什么编译器不能使用这种类型的随机数(或者例如从第一个返回)?
      • @idclev463035818,rustyx 的回答解释。谢谢。
      【解决方案4】:

      您的第二个表达式可能与第一个表达式不同。 decltypeauto有不同的扣减规则。

      要获得相同的返回类型,您必须这样写:

      templtate <typename L, typename R>
      auto getsum(L l, R r) -> decltype(auto) { return l + r; }
      

      现在来看看两者的优势

      第二个sn-p的好处是不重复表达。如果您有复杂的表达式,重复表达式可能会非常麻烦。

      第一个版本的优点是编译器可以对返回类型中的表达式执行SFINAE。

      在 C++20 中,您可以只使用概念来正确地约束函数:

      auto getsum(arithmetic auto l, arithmetic auto r) {
          return l + r;
      }
      

      【讨论】:

        猜你喜欢
        • 2018-08-24
        • 1970-01-01
        • 1970-01-01
        • 2021-06-23
        • 2023-02-22
        • 1970-01-01
        • 2018-08-07
        • 1970-01-01
        • 2018-06-08
        相关资源
        最近更新 更多