C ++ 11中未使用的参数


79

在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标准会出现更好的解决方案吗?我的意思是可以摆脱宏吗?

谢谢大家!


11
当然。关闭警告。
皮特·贝克尔

65
没有!不要那样做!
Lightness Races in Orbit

9
该宏比内联扩展要好多少?(void)argc;UNUSED(argc);
DavidRodríguez-dribeas

22
我喜欢unused(argc, argv)template<class... T> void unused(T&&...){}。清晰,简洁且没有宏。
Xeo

19
@MadScientist,但您可以保留未命名的参数,甚至只是注释掉它的名称。void foo(int /*unused_arg*/, int used_arg)
kassak

Answers:


41

我为此使用了一个带有空主体的函数:

template <typename T>
void ignore(T &&)
{ }

void f(int a, int b)
{
  ignore(a);
  ignore(b);
  return;
}

我希望任何认真的编译器都能优化该函数的调用,并且对我而言是无声的。


20
whenT是模板参数,T&&是绑定到任何内容的通用引用
Angew不再为2012年

4
+1即使Xeo的评论中的高级版本都没有提及。
Christian Rau

12
为什么忽略内置方法?只需省略参数名称。
杰克·艾德利

27
-1,这很荒谬,没有必要,特别是当您可以省略参数名称时。坦白说,这让我不安,因为它有25种投票。
TC1 2013年

5
@ TC1这使您的代码明确说明其作用及其原因。拥有未使用的参数或变量是代码中的一种气味,这使它变得明确。关闭警告会使您的代码闻起来更多。
dascandy

204

您可以省略参数名称:

int main(int, char *[])
{

    return 0;
}

在main的情况下,您甚至可以完全省略参数:

int main()
{
    // no return implies return 0;
}

请参阅C ++ 11标准中的“§3.6开始和终止”。


12
对于main,您可以完全省略参数。并return声明,为这一问题。
Mike Seymour

4
@MikeSeymour我实际上认为省略return语句是一种好习惯。
jtepe

6
@jotep好吧,我咬一口。您为什么认为这是一种好习惯?
彼得·伍德

6
我几乎总是省略mainreturn 0一个测试用例,但几乎总是写自我记录return EXIT_SUCCESS在生产代码。是好习惯!
Lightness Races in Orbit

30
这似乎对我来说是最好的答案-带有宏或模板的内容仍然无法确保以后不能使用该变量。这既使警告静音,确保永远不能使用(未命名)参数。
Alnitak

51

还有就是<tuple>C ++ 11,其中包括准备使用std::ignore对象,这让我们写(很可能不附加任何运行时开销):

void f(int x)
{
    std::ignore = x;
}

4
考虑到这是在标准库中,因此不必编写自定义函数,我会说这是最好的解决方案!
BrainStone

2
此类是“打算在解包std :: tuple时与std :: tie一起使用”,而不是针对此用例。我会说这是一个解决方案,但可能不是最好的。
Maestro

1
我实际上喜欢忽略它。Ofc,如果您可以删除参数,则改为删除它(这将是所有情况下的最佳解决方案)。
危险89年

33

要“禁用”此警告,最好是避免编写参数,只需编写类型。

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 )
{
}

2
我曾经这样做,但由于您无法再使用/* ... */
-Ponkadoodle

1
是的,但是对于现代IDE,我想如果您选择一个要自动注释的块,它将在每行的开头添加一堆“ //”。这就是Eclipse CDT所做的。就个人而言,我只使用第一个没有名称的示例。(例如,您可以将名称放入.h文件的声明中)。
日航2014年

5
@Wallacoloo当我想注释掉大部分代码时,我使用#if 0 ... #endif,它们可以嵌套,并且永远不会与现有的/ * ... * /注释冲突。
德米特里·弗兰克

1
@DmitryFrank大多数#if 0情况下,即使它们不支持完整的预处理器智能感知,大多数编辑器和IDE都支持将其显示为灰色。
托马斯

30

没有什么等同的,没有。

因此,您会遇到相同的旧选项。您是否愿意完全省略参数列表中的名称?

int main(int, char**)

main当然,在的特定情况下,您可以简单地省略参数本身:

int main()

还有一些典型的特定于实现的技巧,例如GCC __attribute__((unused))


14

宏可能不是理想的,但是对于此特定目的,它们做得很好。我会坚持使用宏。


6
+1:在这种情况下,它们造成零伤害并解决问题。我没有任何理由(除了“从不使用宏”这样荒谬的毫无根据的口头禅)不雇用他们。
Lightness Races in Orbit

1
与完全省略参数名称相比,宏有什么好处?
Micha Wiedenmann

1
@MichaWiedenmann:仅当设置了一些预处理常量时才可以使用某些参数(通常在Debug中)。
Matthieu M.

2
@MatthieuM .:MAYBE_UNUSED由于这个原因,我称宏为;我通常不在乎我是否曾说过“如果我不在下面使用它,请不要担心”,但无论如何还是要这样做。
Lightness Races in Orbit

2
好的,所以正确的做法可能是将其称为“ HIDE_UNUSED_WARNING”。但是我仍然认为在这里使用宏是一个完全有效的想法。只要宏的命名方式不会引起混淆和/或与其他代码冲突。
Mats Petersson

13

您对旧的标准方法有什么看法?

void f(int a, int b)
{
  (void)a;
  (void)b;
  return;
}

我发现有些编译器对此感到满意,但是 有些编译器比其他编译器更挑剔。跨平台的工作需要在所有目标OS和编译器中进行测试,以确保他们都对该解决方案感到满意。
杰西·奇斯霍尔姆

12

没有可用的新内容。

对我来说最有效的方法是在实现中注释掉参数名称。这样,您可以摆脱警告,但仍保留有关参数含义的一些概念(因为名称可用)。

您的宏(以及其他所有强制转换为空的方法)的缺点是,使用宏后实际上可以使用该参数。这会使代码难以维护。


12

<boost/core/ignore_unused.hpp>为此,Boost头(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]]禁止对未使用的实体发出警告的属性。


1
[[maybe_unused]]是明确的方式,目前是最好的。
Tomilov Anatoliy

0

我真的很喜欢为此使用宏,因为当您使用其他调试版本时(例如,如果要在启用断言的情况下进行构建),它可以使您更好地控制:

#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;
}

0

对于时间紧迫的代码段,我有自己的实现。我一直在研究时间紧迫的代码以减慢速度,发现该实现比我优化的时间紧迫的代码消耗了大约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 ?表达式出人意料地有助于优化代码。


-1

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;
}

6
这不是一个很好的选择,因为operator=可能会有副作用。
塔马斯·塞莱伊'16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.