【问题标题】:Is the new C++ return syntax limited?新的 C++ 返回语法是否受到限制?
【发布时间】:2016-11-27 05:24:58
【问题描述】:

我开始了一个新的私人项目,并决定这次使用更多C++11/14。所以我也开始使用新的返回语法

auto functionName() -> returnType;

它在大多数情况下工作得很好,但现在我需要一些错误处理并且不知道如何重写这样的东西:

virtual const char* what() const noexcept override;

使用新语法。是否存在无法使用新语法的情况,或者我只是不够聪明,无法找到正确的顺序?对我来说,保持一致很重要,所以我希望问题更多地出现在我这边。

【问题讨论】:

  • 对于 noexcept 见这里:stackoverflow.com/questions/16598320/…
  • 新的返回类型实际上是一种允许在函数参数上使用 decltype() 的技巧。由于函数参数只能在声明它们之后在 decltype 中使用,因此不能将这样的构造放置在返回类型的“旧”位置 - 所以他们移动了返回类型。在我看来,这对编译器编写者的帮助太大了,但代价是整个语言对其他人的可用性降低了。无论如何,您没有意识形态上的理由将整个项目转换为“新”语法;它本身并不更好或更现代。
  • 我不知道有什么理由在非泛型代码中使用尾随返回类型语法,除非您认为它看起来更好。有一些 C++11 特性,如 auto 或大括号初始化,可以说是为了在所有“现代”代码中“默认”使用,但我很确定尾随返回类型只存在于支持某个子集以前无法编写的类型安全通用代码。
  • @lxrec:我确实发现它在以下情况下很有用:假设我想声明某个类的成员函数并在编译时将它们注册到某个地方。为了避免大量的样板,我可能会使用宏。然而,如果一个宏开始一个函数声明,它还必须包括返回类型,因为它出现在函数名之后。如果您使用尾随返回类型语法,则可以缓解这种情况。宏可以对&my_type::NAME 执行某些操作,然后还声明auto NAME 并让用户指定签名,如果他们愿意,还可以指定定义。
  • @KerrekSB OP 从未声称,甚至明确表示(请参阅 11 和 14 后面的链接)这个问题适用于两者。请不要再吹毛求疵了吗?

标签: c++ c++11 return


【解决方案1】:

由于您也询问过 C++14,对于您的场景,这比后缀返回类型语法要好;

virtual auto what() const noexcept override;

【讨论】:

  • ... 在允许您完全省略返回类型的情况下(例如,当您有多个 return 语句时,它可能是非法的)
【解决方案2】:

问题的原因是noexcept 是函数声明符的一部分(并且建议成为C++17 中函数类型的一部分),而override 是一个(可选使用的)标识符,它不是函数声明器的一部分。

因此,如果不使用override,则声明将是

virtual auto what() const noexcept -> const char *;

而且,由于override 必须出现在此声明之后,因此会导致

virtual auto what() const noexcept -> const char * override;

也就是说,与其盲目地使用 C++11/C++14 功能,不如选择最能反映您意图的功能。如果有较旧的替代方案来实现相同的目标,则没有某些规则要求仅使用 C++11/C++14 功能。

【讨论】:

    【解决方案3】:

    新语法支持旧语法所做的一切。

    virtual const char* what() const noexcept override;
    

    必须改写为

    virtual auto what() const noexcept -> const char * override;
    

    实际上,新语法支持更多功能:

    • 它允许您对函数参数执行decltype

      template <typename A, typename B> auto plus(A a, B b) -> decltype(a+b)
      {
          return A + B;
      }
      
    • 它还允许您对this 执行decltype,这反过来又允许您对成员函数执行decltypeSee this.

      struct S
      {
          int a() {return 1;}
          auto b() -> decltype(a()) {return 2;} // Works.
          decltype(a()) c() {return 2;} // ERROR.
      };
      

    虽然新语法具有所有这些附加功能,但它不应该替代旧语法。至少我是这样理解的。

    一些程序员更喜欢使用它,但据我所知,StackOverflow 上的大多数程序员更喜欢尽可能使用旧语法。

    【讨论】:

    • 特别是尾随返回类型允许您使用在类中定义的类型,在返回类型中没有限定。
    【解决方案4】:

    是的,这不是你通常会猜到的。

    virtual auto what() const noexcept -> const char * override;
    

    这只是您必须使用的顺序。语法可能会有所不同,但这就是我们所拥有的。

    【讨论】:

    • 呃。为什么有人认为这是优越的?它当然不是更具可读性。这种表示法只应在有限的情况下使用,例如真正需要的模板。
    • 为什么语法应该不同?新语法延迟了返回类型,而不是限定符或其他东西……“virtual”、“const”、“override”和“noexcept”不是返回类型的一部分,所以它们留在原处是。
    • @CodyGray 没有人会说这里的新语法更干净。我建议在这种情况下不要使用它。它是为需要在范围内具有类型函数参数以形成返回类型的泛型代码引入的。这不是审美原因。啊,当然对于 lambdas ......
    • 来自 Swift(使用“throws”而不是否定的“noexcept”),语法对我来说似乎很自然。我是这样看的:在映射(箭头)成功之前发生异常/错误。也许是因为“noexcept”是一个否定词,而我们人类不擅长否定?
    • @RandyMarsh 这对我来说没有意义,也不是因为noexcept 是一个否定词,而是因为它没有任何区别首先被解析。在编译时,两者都需要继续编译过程,并且任何一个顺序都可以工作。在运行时,也不是哪个先出现的问题:可能会抛出异常,可能会返回一个值,但绝不会两者兼而有之。也许 Swift 的工作方式不同,在这种情况下,我根本不明白你的意思。
    猜你喜欢
    • 2016-07-30
    • 2019-12-28
    • 2014-01-12
    • 1970-01-01
    • 2012-06-12
    • 2012-10-31
    • 2014-06-30
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多