W c ++ 03 i wcześniejszych, aby wyłączyć ostrzeżenie kompilatora o nieużywanym parametrze, zwykle używam takiego kodu:
#define UNUSED(expr) do { (void)(expr); } while (0)
Na przykład
int main(int argc, char *argv[])
{
UNUSED(argc);
UNUSED(argv);
return 0;
}
Ale makra nie są najlepszą praktyką dla języka C ++, więc. Czy w standardzie C ++ 11 pojawia się lepsze rozwiązanie? Mam na myśli, czy mogę pozbyć się makr?
Dzięki za wszystko!
c++
c++11
unused-variables
inkooboo
źródło
źródło
(void)argc;
jest krótszy i wyraźniejszy niżUNUSED(argc);
unused(argc, argv)
ztemplate<class... T> void unused(T&&...){}
. Jasne, zwięzłe i bez makr.void foo(int /*unused_arg*/, int used_arg)
Odpowiedzi:
W tym celu użyłem funkcji z pustą treścią:
template <typename T> void ignore(T &&) { } void f(int a, int b) { ignore(a); ignore(b); return; }
Oczekuję, że każdy poważny kompilator zoptymalizuje wywołanie funkcji i wyciszy ostrzeżenia dla mnie.
źródło
T
jest parametrem szablonu,T&&
to uniwersalne odniesienie, które wiąże się ze wszystkim.Możesz po prostu pominąć nazwy parametrów:
int main(int, char *[]) { return 0; }
A w przypadku main możesz nawet całkowicie pominąć parametry:
int main() { // no return implies return 0; }
Zobacz „§ 3.6 Rozpoczęcie i zakończenie” w standardzie C ++ 11.
źródło
main
możesz całkowicie pominąć parametry. Ireturn
oświadczenie, jeśli o to chodzi.main
„sreturn 0
w TestCase, ale prawie zawsze napisać własny dokumentowaniereturn EXIT_SUCCESS
w kodzie produkcyjnym. To dobra praktyka!Jest
<tuple>
w C ++ 11 , który zawiera gotowy do użyciastd::ignore
obiekt, który pozwala nam pisać (najprawdopodobniej bez nakładania narzutów czasu wykonania):void f(int x) { std::ignore = x; }
źródło
Aby „wyłączyć” to ostrzeżenie, najlepiej jest unikać wpisywania argumentu, wystarczy wpisać typ.
void function( int, int ) { }
lub jeśli wolisz, skomentuj to:
void function( int /*a*/, int /*b*/ ) { }
Możesz łączyć argumenty nazwane i nienazwane:
void function( int a, int /*b*/ ) { }
W C ++ 17 masz specyfikator atrybutu [[może_unused]], na przykład:
void function( [[maybe_unused]] int a, [[maybe_unused]] int b ) { }
źródło
/* ... */
#if 0
bloków jako przypadek specjalny, nawet jeśli nie obsługują one pełnej inteligencji preprocesora.Nic równoważnego, nie.
Więc utkniesz z tymi samymi starymi opcjami. Czy z przyjemnością całkowicie pomijasz nazwy na liście parametrów?
int main(int, char**)
W konkretnym przypadku
main
oczywiście można po prostu pominąć same parametry:int main()
Istnieją również typowe sztuczki specyficzne dla implementacji, takie jak GCC
__attribute__((unused))
.źródło
Makra mogą nie być idealne, ale sprawdzają się w tym konkretnym celu. Powiedziałbym, że trzymaj się makra.
źródło
MAYBE_UNUSED
tego powodu zadzwoniłbym do makra ; Zwykle nie obchodzi mnie, czy powiedziałem „nie martw się, jeśli nie użyję tego poniżej”, ale i tak kontynuuj.Co masz przeciwko starym i standardowym sposobom?
void f(int a, int b) { (void)a; (void)b; return; }
źródło
Nie ma nic nowego.
Najlepiej dla mnie jest zakomentowanie nazwy parametru w implementacji. W ten sposób pozbędziesz się ostrzeżenia, ale nadal zachowasz pewne pojęcie o tym, jaki jest parametr (ponieważ nazwa jest dostępna).
Twoje makro (i każde inne podejście typu rzutowanie na próżnię) ma tę wadę, że faktycznie możesz użyć parametru po użyciu makra. Może to utrudnić utrzymanie kodu.
źródło
W
<boost/core/ignore_unused.hpp>
tym celu nagłówek Boost (Boost> = 1.56) definiuje szablon funkcjiboost::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 ma
[[maybe_unused]]
atrybut pomijania ostrzeżeń o nieużywanych jednostkach.źródło
[[maybe_unused]]
jest jednoznaczny, obecnie najlepszy.Bardzo lubię używać do tego makr, ponieważ pozwala to na lepszą kontrolę, gdy masz różne kompilacje debugowania (np. Jeśli chcesz budować z włączonymi assertami):
#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
a następnie użyj go jak:
int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar)) { MY_ASSERT(myChar < 12.0f); return myInt; }
źródło
Mam własną implementację dla krytycznych czasowo segmentów kodu. Przez jakiś czas badałem kod krytyczny czasowo dla spowolnienia i odkryłem, że ta implementacja pochłania około 2% czasu krytycznego kodu, który został zoptymalizowany:
#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
Kod krytyczny czasowo używał
ASSERT*
definicji do celów debugowania, ale w wydaniu wyraźnie został odcięty, ale ... Wygląda na to, że ten tworzy nieco szybszy kod wVisual 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)
Powód ma podwójny
false ?
wyraz. W jakiś sposób generuje nieco szybszy kod przy maksymalnej optymalizacji.Nie wiem, dlaczego jest to szybsze (wydaje się, że jest to błąd w optymalizacji kompilatora), ale przynajmniej jest to lepsze rozwiązanie dla tego przypadku kodu.
Uwaga : Najważniejsze jest to, że krytyczny czasowo kod zwalnia bez powyższych potwierdzeń lub nieużywanych makr w wydaniu. Innymi słowy, podwójne
false ?
wyrażenie w zaskakujący sposób pomaga zoptymalizować kod.źródło
windows.h definiuje UNREFERENCED_PARAMETER :
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
Więc możesz to zrobić w ten sposób:
#include <windows.h> #include <stdio.h> int main(int argc, char **argv) { UNREFERENCED_PARAMETER(argc); puts(argv[1]); return 0; }
Lub poza systemem Windows:
#include <stdio.h> #define UNREFERENCED_PARAMETER(P) {(P) = (P);} int main(int argc, char **argv) { UNREFERENCED_PARAMETER(argc); puts(argv[1]); return 0; }
źródło
operator=
może mieć skutki uboczne.