Неиспользуемый параметр в С++ 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;
}