c++11中未使用的参数
Posted
技术标签:
【中文标题】c++11中未使用的参数【英文标题】:Unused parameter in c++11 【发布时间】:2013-04-02 12:18:17 【问题描述】:在 c++03 及更早版本中,为了禁用关于未使用参数的编译器警告,我通常使用这样的代码:
#define UNUSED(expr) do (void)(expr); while (0)
例如
int main(int argc, char *argv[])
UNUSED(argc);
UNUSED(argv);
return 0;
但是宏不是 C++ 的最佳实践,所以。 c++11标准有没有更好的解决方案?我的意思是我可以摆脱宏吗?
谢谢大家!
【问题讨论】:
当然。关闭警告。 不! 不要那样做! 这个宏比内联扩展好多少?(void)argc;
比 UNUSED(argc);
更短更清晰
我喜欢unused(argc, argv)
和template<class... T> void unused(T&&...)
。清晰、简洁且没有宏。
@MadScientist 但您可以留下未命名的参数,甚至只是注释掉它的名称。 void foo(int /*unused_arg*/, int used_arg)
【参考方案1】:
你可以省略参数名称:
int main(int, char *[])
return 0;
而在 main 的情况下,你甚至可以完全省略参数:
int main()
// no return implies return 0;
请参阅 C++11 标准中的“§ 3.6 开始和终止”。
【讨论】:
而在main
的情况下,可以完全省略参数。还有return
声明。
@MikeSeymour 实际上我认为省略 return 语句是一种好习惯。
@jotep 好的,我会咬一口的。为什么您认为这是一种很好的做法?
我几乎总是在测试用例中省略 main
的 return 0
,但几乎总是在生产代码中编写自记录 return EXIT_SUCCESS
。 这是的好习惯!
这对我来说似乎是最好的答案 - 任何使用宏或模板的东西仍然不能确保以后不能使用该变量。这既可以消除警告 并且 确保永远不能使用(未命名的)参数。【参考方案2】:
C++11 中有 <tuple>
,其中包括准备使用的 std::ignore
对象,这允许我们编写(很可能不会产生运行时开销):
void f(int x)
std::ignore = x;
【讨论】:
考虑到这是在标准库中,因此不需要编写自定义函数我会说这是最好的解决方案! 此类是“在解压 std::tuple 时用于 std::tie”,不适用于此用例。我会说这是一个解决方案,但可能不是最好的。 我喜欢这个忽略实际上.. Ofc,如果你可以删除参数,请删除它(这将是所有情况下的最佳解决方案)。【参考方案3】:为此,我使用了一个带有空主体的函数:
template <typename T>
void ignore(T &&)
void f(int a, int b)
ignore(a);
ignore(b);
return;
我希望任何认真的编译器都能优化函数调用,并为我消除警告。
【讨论】:
当T
是一个模板参数时,T&&
是一个绑定到任何东西的通用引用。
+1 即使他的评论中没有提到 Xeo 的高级版本。
为什么忽略内置方法?只需省略参数名称即可。
-1,这很荒谬,而且是不必要的装置,尤其是当您可以省略参数名称时。坦率地说,这让我很困扰,不知何故有 25 个赞成票。
@TC1 这使您的代码明确说明它的作用和原因。有未使用的参数或变量是你的代码中的一种气味,这使它变得明确。关闭警告会让你的代码更臭。【参考方案4】:
要“禁用”这个警告,最好避免写参数,只写类型。
void function( int, int )
或者,如果您愿意,可以将其注释掉:
void function( int /*a*/, int /*b*/ )
您可以混合使用命名和未命名的参数:
void function( int a, int /*b*/ )
使用 C++17 你有 [[maybe_unused]] 属性说明符,例如:
void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
【讨论】:
我曾经这样做过,但很快就变得很痛苦,因为你不能再用/* ... */
注释掉大块代码
这是真的,但是对于现代 IDE,我猜如果你选择一个块来自动注释,它会在每行的开头添加一堆“//”。这就是 Eclipse CDT 所做的。就个人而言,我只使用第一个没有名字的例子。 (例如,您可以将名称放在 .h 文件中的声明中)。
@Wallacoloo 当我想注释掉一大块代码时,我使用#if 0 ... #endif,它允许嵌套并且永远不会与现有的/* ... */冲突厘米。
@DmitryFrank 大多数编辑器和 IDE 都支持将 #if 0
块灰显作为一种特殊情况,即使它们不支持完整的预处理器智能感知。【参考方案5】:
没有等价物,没有。
因此,您会遇到相同的旧选项。您愿意完全省略参数列表中的名称吗?
int main(int, char**)
在main
的具体情况下,当然可以直接省略参数本身:
int main()
还有典型的特定于实现的技巧,例如 GCC 的__attribute__((unused))
。
【讨论】:
【参考方案6】:宏可能并不理想,但它们可以很好地实现这一特定目的。我会说坚持使用宏。
【讨论】:
+1:在这种情况下,它们会造成零伤害并解决问题。我看不出有任何理由(除了“永远不要使用宏”的荒谬毫无根据的口头禅)不在这里使用它们。 宏与完全省略参数名称相比有什么好处? @MichaWiedenmann:某些参数只能在设置了某些预处理常量时使用(通常在 Debug 中)。 @MatthieuM.:出于这个原因,我将调用宏MAYBE_UNUSED
;我通常不在乎我是否说过“如果我在下面不使用它,请不要担心”,但无论如何都会继续这样做。
好的,所以正确的做法可能是称之为“HIDE_UNUSED_WARNING”。但我仍然认为在这里使用宏是一个完全有效的想法。只要宏的命名方式不会引起混淆和/或与其他代码冲突。【参考方案7】:
你对旧的和标准的方式有什么看法?
void f(int a, int b)
(void)a;
(void)b;
return;
【讨论】:
我发现一些编译器对此很满意,但 一些 编译器比其他编译器更挑剔。跨平台工作需要在所有目标操作系统和编译器中进行测试,以确保他们都对解决方案感到满意。【参考方案8】:Boost 标头 <boost/core/ignore_unused.hpp>
(Boost >= 1.56) 为此定义了函数模板 boost::ignore_unused()
。
int fun(int foo, int bar)
boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
if (foo < bar)
std::cerr << "warning! foo < bar";
#endif
return foo + 2;
PS C++17 有 [[maybe_unused]]
属性来抑制未使用实体的警告。
【讨论】:
[[maybe_unused]]
是显式方式,目前最好。【参考方案9】:
没有新的可用。
最适合我的是在实现中注释掉参数名称。这样,您就可以摆脱警告,但仍然保留一些关于参数是什么的概念(因为名称可用)。
您的宏(以及所有其他强制转换为 void 的方法)的缺点是您可以在使用宏后实际使用参数。这会使代码更难维护。
【讨论】:
【参考方案10】:我真的很喜欢为此使用宏,因为它可以让您更好地控制何时有不同的调试版本(例如,如果您想在启用断言的情况下进行构建):
#if defined(ENABLE_ASSERTS)
#define MY_ASSERT(x) assert(x)
#else
#define MY_ASSERT(x)
#end
#define MY_UNUSED(x)
#if defined(ENABLE_ASSERTS)
#define MY_USED_FOR_ASSERTS(x) x
#else
#define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end
然后像这样使用它:
int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
MY_ASSERT(myChar < 12.0f);
return myInt;
【讨论】:
【参考方案11】:对于时间关键的代码段,我有自己的实现。 我一直在研究用于减速的时间关键代码,发现此实现消耗了我正在优化的时间关键代码的 2%:
#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) UTILITY_UNUSED2(v1, v2); (void)0
时间紧迫的代码已将ASSERT*
定义用于调试目的,但在发布时它显然已被删除,但是......似乎这个在Visual Studio 2015 Update 3
中产生了更快的代码:
#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)
原因在于双重false ?
表达式。它以某种方式在发布时产生了更快的代码,并进行了最大程度的优化。
我不知道为什么这更快(似乎是编译器优化中的一个错误),但对于这种代码情况,它至少是一个更好的解决方案。
注意:
这里最重要的是,时间关键代码会减慢没有上述断言或发布中未使用的宏。换句话说,双重false ?
表达式有助于优化代码。
【讨论】:
【参考方案12】:windows.h 定义了 UNREFERENCED_PARAMETER:
#define UNREFERENCED_PARAMETER(P) (P) = (P);
所以你可以这样做:
#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv)
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
或在 Windows 之外:
#include <stdio.h>
#define UNREFERENCED_PARAMETER(P) (P) = (P);
int main(int argc, char **argv)
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
【讨论】:
这不是一个很好的选择,因为operator=
可能有副作用。以上是关于c++11中未使用的参数的主要内容,如果未能解决你的问题,请参考以下文章
获取 BitcoinLib 错误 = “在配置文件中未找到 CoinParameters 中定义的一个或多个必需参数!”