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 好的,我会咬一口的。为什么您认为这是一种很好的做法? 我几乎总是在测试用例中省略 mainreturn 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&amp;&amp; 是一个绑定到任何东西的通用引用 +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 标头 &lt;boost/core/ignore_unused.hpp&gt; (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中未使用的参数的主要内容,如果未能解决你的问题,请参考以下文章

Oracle11g版本中未归档隐藏参数

宏中未使用的参数会怎样?

获取 BitcoinLib 错误 = “在配置文件中未找到 CoinParameters 中定义的一个或多个必需参数!”

泛型类中未使用的类型参数

Python:使用参数(变量)执行shell脚本,但在shell脚本中未读取参数

应用程序中未找到服务器 404 以从 api 读取数据但不传递参数它可以工作