c++11中未使用的参数

Unused parameter in c++11

本文关键字:参数 未使用 c++11      更新时间:2023-10-16

在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标准有没有更好的解决方案?我的意思是我能摆脱宏吗?

谢谢大家!

可以省略参数名:

int main(int, char *[])
{
    return 0;
}

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

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

参见c++ 11标准中的"§3.6 Start and Termination"

c++ 11中有<tuple>,其中包括准备使用std::ignore对象,这允许我们编写(很可能不会强加运行时开销):

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

我使用了一个空体函数:

template <typename T>
void ignore(T &&)
{ }
void f(int a, int b)
{
  ignore(a);
  ignore(b);
  return;
}

我希望任何严肃的编译器都能优化函数调用,它会为我静音警告。

要"禁用"此警告,最好是避免写参数,只写类型。

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

没有,没有。

所以你被困在相同的旧选项。您是否愿意完全省略参数列表中的名称?

int main(int, char**)

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

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

你对传统的标准方式有什么不满?

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

宏可能不是理想的,但是它们在这个特定的目的上做得很好。我觉得还是用宏吧

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

psc++ 17有[[maybe_unused]]属性来抑制对未使用实体的警告。

没有新的可用

对我来说最有效的是注释掉实现中的参数名。这样,您就可以摆脱警告,但仍然保留了参数是什么的一些概念(因为名称是可用的)。

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

我真的很喜欢使用宏,因为它可以让你更好地控制当你有不同的调试构建(例如,如果你想构建与断言启用):

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

对于时间关键的代码段,我有自己的实现。我一直在研究一个时间关键代码的减速,并发现这个实现消耗了大约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 ?表达式中。它以某种方式在最大优化的情况下产生更快的代码。

我不知道为什么这样更快(似乎是编译器优化中的一个bug),但它至少是这种情况下代码的更好解决方案。

注意:这里最重要的是,如果没有上面的断言或未使用的宏,时间关键型代码会减慢的速度。换句话说,双false ?表达式出人意料地有助于优化代码。

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