Неиспользуемый параметр в С++ 11

В С++ 03 и ранее для отключения предупреждения компилятора о неиспользуемом параметре я обычно использую такой код:

#define UNUSED(expr) do { (void)(expr); } while (0)

Например

int main(int argc, char *argv[])
{
    UNUSED(argc);
    UNUSED(argv);

    return 0;
}

Но макросы не являются лучшей практикой для С++, так что. Появляется ли какое-либо лучшее решение с стандартом С++ 11? Я имею в виду, могу ли я избавиться от макросов?

Спасибо всем!

Ответ 1

Я использовал функцию с пустым телом для этой цели:

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

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

Я ожидаю, что любой серьезный компилятор будет оптимизировать вызов функции, и он отключит предупреждения для меня.

Ответ 2

Вы можете просто опустить имена параметров:

int main(int, char *[])
{

    return 0;
}

И в случае main вы можете вообще опустить параметры:

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

См. "§ 3.6 Начало и завершение" в стандарте С++ 11.

Ответ 3

В С++ 11 есть <tuple>, который включает в себя готовый к использованию объект std::ignore, который позволяет нам писать (очень вероятно, не налагая накладные расходы во время исполнения):

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

Ответ 4

Ничего эквивалентного, нет.

Итак, вы застряли с теми же старыми опциями. Вы счастливы полностью опустить имена в списке параметров?

int main(int, char**)

В конкретном случае main, конечно, вы можете просто опустить сами параметры:

int main()

Существуют также типичные трюки, специфичные для реализации, такие как GCC __attribute__((unused)).

Ответ 5

Чтобы "отключить" это предупреждение, лучше всего избегать написания аргумента, просто напишите тип.

void function( int, int )
{
}

или, если вы предпочитаете, закомментируйте это:

void function( int /*a*/, int /*b*/ )
{
}

Вы можете смешивать именованные и безымянные аргументы:

void function( int a, int /*b*/ )
{
}

В С++ 17 у вас есть [[Maybe_unused]] атрибут-атрибут, например:

void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}

Ответ 6

Макросы могут быть не идеальными, но они хорошо подходят для этой конкретной цели. Я бы сказал, придерживаться использования макроса.

Ответ 7

Что вы имеете против старого и стандартного пути?

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

Ответ 8

Нет ничего нового.

Что лучше всего подходит для меня - это прокомментировать имя параметра в реализации. Таким образом, вы избавляетесь от предупреждения, но сохраняете некоторое представление о том, что такое параметр (поскольку имя доступно).

У вашего макроса (и любого другого подхода, отличного от void) есть недостаток, который можно использовать параметр после использования макроса. Это может сделать код более сложным для поддержания.

Ответ 9

Заголовок 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 С++ 17 имеет атрибут [[maybe_unused]] для подавления предупреждений о неиспользуемых объектах.

Ответ 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;
}