【问题标题】:How to mark a constexpr function's parameter unused?如何将 constexpr 函数的参数标记为未使用?
【发布时间】:2015-10-25 07:41:24
【问题描述】:

考虑这个经典的例子:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N]) noexcept { return N; }

现在这工作正常,但有一个烦恼,gcc 给出警告:

warning: unused parameter ‘array’ [-Wunused-parameter]

已知解决方案:

  • 不起作用:如果我将经典的(void)arr; 添加到函数中,我会得到error: body of constexpr function ‘...‘ not a return-statement
  • 不满意:我可以有arraySize(T (&amp;)[N]),但我想命名参数有两个原因:
    1. 它使编译器错误消息更易于理解。
    2. 更主观地说,我认为它使代码更清晰,尤其是对于那些不喜欢这种语法的人。
  • 不好:在这个特定的例子中,我也可以return sizeof(array)/sizeof(array[0]);,但这种方法不是通用的解决方案,而且我认为return N; 更好,肯定更容易看到。
  • 很好,但并非总是可行:切换到使用 C++14 和完全支持它的编译器。那么像{ (void)array; return N; }这样的constexpr函数体是允许的。

如何在使用 C++11 时很好地消除未使用参数警告

【问题讨论】:

  • 我不在我的笔记本电脑前,但简单地使用arraySize(T*)(没有名字你不需要它)不能解决吗?当然,用正确的类型,对不起,如果我不能为你试一试......
  • arraySize(T(&amp;)[N])?这应该可行,但我不确定警告,因为我无法尝试。如果没问题,我会回复的。
  • 哦,对不起,我的错。好吧,如果您坚持为参数命名,编译器将继续发出警告,除非您说服它关于您的解决方案项目符号 2... :-) ... 否则,请使用 return arr ? N : N; 之类的东西,我'我非常有信心编译器会在运行时摆脱它而不会出现性能问题。
  • @hyde return (void)array, N; 怎么样?
  • 很好奇:如果 C++14 选项关闭,那么使用不带尾随返回类型的 auto 不应该编译;如果 C++14 开启,那么(void)arr; 应该没问题。

标签: c++ c++11 constexpr


【解决方案1】:

试试这个。我有时会使用这种方法

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }

【讨论】:

  • 您是否阅读了@skypjack 的问题或答案?
  • @m.s.是的,我没有读到最后的答案。我会在十分钟内更正或删除我的答案
  • 我最喜欢这个解决方案,因为它不会像其他答案那样引入任何可能使读者感到困惑的不必要的逻辑。
【解决方案2】:

我建议以下(ab)使用逗号运算符:

return (void)array, N;

【讨论】:

  • 在问题的限制范围内,我最喜欢这个,因为它实际上不应该评估任何东西。添加// void cast with comma operator for C++11 compatiblity之类的评论可能是明智之举
  • @hyde 是的,用注释记录(相对)奇怪的返回表达式可能是个好主意。
【解决方案3】:

对于新的谷歌员工:

C++17 添加了一个[[maybe_unused]] 属性,可以这样使用:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }

【讨论】:

    【解决方案4】:

    最好的解决方案是第二点禁止的,即使用T(&amp;)[N]

    注释中的另一种可能的方法是使用以下返回值:

    return array ? N : N;
    

    我很确定编译器会摆脱它,并且在运行时不会出现性能问题。

    【讨论】:

    • 如果你想抑制编译器警告,那么使用#pragma 来抑制它。无缘无故地引用参数而不是抑制编译器警告与编写清晰可读的代码相反。
    • 我宁愿使用没有变量名的唯一类型,这比杂注要清楚得多,但他有一些限制(见问题),这是一种可能且可移植的解决方案,没有更多。
    【解决方案5】:

    正如@fnc12 和@skypjack 都指出的那样,消除未使用参数编译器警告的惯用方法是不给参数命名。

    constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
    

    使用/**/ cmets 解决了可读性异议。它不会在编译器消息中修复名称,但我认为最有可能出现的情况是“未声明的标识符”,一旦您注意到标识符被注释,这很容易解决。

    如果您真的不喜欢惯用的方式,那么只需抑制警告(如果您的编译器允许,则在本地)。

    Suppressing warnings in GCC using #pragma GCC diagnostic.

    Suppressing warnings in Visual Studio using #pragma warning suppress

    我建议不要在代码中添加“虚拟”引用来关闭编译器。无缘无故地引用一个其他未使用的参数,而不是抑制编译器警告,这会不必要地增加代码的复杂性,并且会使未来的维护者混淆它为什么存在。

    【讨论】:

    • 其实把参数名放到cmets里,至少gcc会显示出来,所以其实也有帮助(当然看起来有点丑……)。我绝对同意从函数 definition 中删除未使用的参数名称。但是IMO声明应该有,这里定义和声明是一样的。
    【解决方案6】:

    gcc 提供了unused attribute,可以如下使用:

    constexpr std::size_t arraySize(__attribute__((unused)) T (&array)[N]) noexcept { return N; }
                                    ^^^^^^^^^^^^^^^^^^^^^^^
    

    Ben Deane recently tweatted about a C++11 way 使用与逗号运算符结合的 lambdas 来抑制此警告看起来像这样:

    #define UNUSED(x) [&x]{}()
    
    //...
    
    return UNUSED(array), N;
    

    【讨论】:

      【解决方案7】:

      未命名的论点是正确的解决方案。

      所以你可以使用中间函数:

      template <typename T>
      constexpr void avoid_warning_for_unused_parameter(T&&) noexcept{}
      

      然后:

      template <typename T, std::size_t N>
      constexpr std::size_t arraySize(T (&array)[N]) noexcept
      {
          avoid_warning_for_unused_parameter(array);
          return N;
      }
      

      对于 C++11,你必须多做一点:

      template <typename... Ts>
      constexpr auto return_first_and_avoid_warning_for_unused_parameters(T&&t, Ts&&) noexcept
      -> decltype(t)
      {
          return t;
      }
      
      template <typename T, std::size_t N>
      constexpr std::size_t arraySize(T (&array)[N]) noexcept
      {
          return return_first_and_avoid_warning_for_unused_parameters(N, array);
      }
      

      【讨论】:

      • 这与仅使用传统的 (void) 转换没有太大区别,因为这也需要 C++14。我可以理解明确命名的“未使用”函数(或宏)的意义,但我个人更喜欢简单的旧传统 (void) 强制转换为额外函数的混乱,因为它是一个非常成熟的习语。 YMMV。
      • @hyde: 根据herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings(void) array 不适用于所有编译器。
      猜你喜欢
      • 2022-09-23
      • 1970-01-01
      • 2015-08-25
      • 2017-12-17
      • 1970-01-01
      • 2023-03-16
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多