如何将 constexpr 函数的参数标记为未使用?
How to mark a constexpr function's parameter unused?
考虑这个经典示例:
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 (&)[N])
,但我想命名参数有两个原因:
- 它使编译器错误消息更易于理解。
- 更主观地说,我认为它使代码更清晰,尤其是对于那些不喜欢这种语法的人。
- 不好:在这个特定的例子中,我也可以
return sizeof(array)/sizeof(array[0]);
,但这种方法不是通用的解决方案,而且我认为 return N;
更好,绝对更美观。
- 很好,但并非总是可行:切换到使用 C++14 和完全支持它的编译器。然后允许像
{ (void)array; return N; }
这样的 constexpr 函数体。
如何在使用 C++11 时很好地消除未使用参数警告?
最好的解决方案是第二点禁止的,即使用T(&)[N]
。
根据评论,另一种可能的方法是使用以下 return 值:
return array ? N : N;
我很确定编译器会摆脱它并且在运行时不会有性能问题。
试试这个。我有时用这个方法
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
正如@fnc12 和@skypjack 所指出的,消除未使用参数编译器警告的惯用方法是不给参数命名。
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
使用 /**/
注释解决了可读性问题。它没有修复编译器消息中的名称,但我认为最有可能由此产生的情况是 "undeclared identifier",一旦您注意到标识符已被注释,这很容易解决。
如果您真的坚决反对惯用的方式,那么只需取消警告(如果您的编译器允许,则在本地)。
Suppressing warnings in GCC using #pragma GCC diagnostic
.
Suppressing warnings in Visual Studio using #pragma warning suppress
我建议不要在代码中添加 "dummy" 引用来关闭编译器。除了抑制编译器警告外,无缘无故地引用一个未使用的参数会不必要地增加代码的复杂性,并且会使未来的维护者困惑为什么它在那里。
我建议逗号运算符的以下(滥用)用法:
return (void)array, N;
未命名的参数是正确的解决方案。
所以你可以使用一个中间函数:
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);
}
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 使用与逗号运算符结合的 lambda 来抑制此警告,如下所示:
#define UNUSED(x) [&x]{}()
//...
return UNUSED(array), N;
对于新的 google 员工:
C++17 添加了一个 [[maybe_unused]]
属性,可以这样使用:
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }
考虑这个经典示例:
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 (&)[N])
,但我想命名参数有两个原因:- 它使编译器错误消息更易于理解。
- 更主观地说,我认为它使代码更清晰,尤其是对于那些不喜欢这种语法的人。
- 不好:在这个特定的例子中,我也可以
return sizeof(array)/sizeof(array[0]);
,但这种方法不是通用的解决方案,而且我认为return N;
更好,绝对更美观。 - 很好,但并非总是可行:切换到使用 C++14 和完全支持它的编译器。然后允许像
{ (void)array; return N; }
这样的 constexpr 函数体。
如何在使用 C++11 时很好地消除未使用参数警告?
最好的解决方案是第二点禁止的,即使用T(&)[N]
。
根据评论,另一种可能的方法是使用以下 return 值:
return array ? N : N;
我很确定编译器会摆脱它并且在运行时不会有性能问题。
试试这个。我有时用这个方法
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
正如@fnc12 和@skypjack 所指出的,消除未使用参数编译器警告的惯用方法是不给参数命名。
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
使用 /**/
注释解决了可读性问题。它没有修复编译器消息中的名称,但我认为最有可能由此产生的情况是 "undeclared identifier",一旦您注意到标识符已被注释,这很容易解决。
如果您真的坚决反对惯用的方式,那么只需取消警告(如果您的编译器允许,则在本地)。
Suppressing warnings in GCC using #pragma GCC diagnostic
.
Suppressing warnings in Visual Studio using #pragma warning suppress
我建议不要在代码中添加 "dummy" 引用来关闭编译器。除了抑制编译器警告外,无缘无故地引用一个未使用的参数会不必要地增加代码的复杂性,并且会使未来的维护者困惑为什么它在那里。
我建议逗号运算符的以下(滥用)用法:
return (void)array, N;
未命名的参数是正确的解决方案。
所以你可以使用一个中间函数:
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);
}
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 使用与逗号运算符结合的 lambda 来抑制此警告,如下所示:
#define UNUSED(x) [&x]{}()
//...
return UNUSED(array), N;
对于新的 google 员工:
C++17 添加了一个 [[maybe_unused]]
属性,可以这样使用:
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }