2015-10-25 9 views
5

Rozważmy to klasyczny przykład:Jak oznaczyć nieużywany parametr funkcji constexpr?

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept { return N; } 

Teraz to działa prawidłowo, ale jest jeden kłopot, gcc daje ostrzeżenie:

warning: unused parameter ‘array’ [-Wunused-parameter] 

znane rozwiązania:

  • robi” t praca: jeśli dodaję klasyczną funkcję (void)arr;, otrzymam error: body of constexpr function ‘...‘ not a return-statement.
  • Niezadowalający: Mogę mieć arraySize(T (&)[N]), ale chcę, aby wymienić argument z dwóch powodów:
    1. To sprawia, że ​​komunikat o błędzie kompilatora bardziej zrozumiałe.
    2. Bardziej subiektywnie, myślę, że czyni to kod jaśniejszym, szczególnie dla tych, którzy nie żyją i oddychają tą składnią.
  • Niezły: W tym konkretnym przykładzie, mogę również return sizeof(array)/sizeof(array[0]);, ale takie podejście nie jest uniwersalnym rozwiązaniem, a także myślę return N; jest o wiele ładniejszy, zdecydowanie łatwiejsze w oku.
  • Dobre, ale nie zawsze możliwe: przełącz na C++ 14 i kompilator, który obsługuje go w pełni. Następnie dozwolone jest ciało funkcji constexpr, takie jak { (void)array; return N; }.

Jak mogę dobrze usunąć ostrzeżenie o nieużywanym parametrze, używając C++ 11?

+0

Nie jestem na moim laptopie, ale po prostu używając 'arraySize (T *)' (bez nazwy dla ciebie nie potrzebujesz tego) nie rozwiązuje? Oczywiście, z odpowiednim typem, przepraszam, jeśli nie mogę spróbować dla ciebie ... – skypjack

+0

@skypjack Jak rozumiem, wymagane jest odwołanie do tablicy. W przeciwnym razie kompilator nie może automatycznie przyznać 'N'. Dlatego 'arraySize (T [N])' nie zadziała (przetestowane, nie skompiluje się bez jawnego podania 'N' jako argumentu szablonu podczas wywoływania funkcji). – hyde

+1

'arraySize (T (&) [N])'? To powinno zadziałać, ale nie jestem pewien ostrzeżenia, bo nie mogę spróbować. Jeśli wszystko będzie dobrze, odpowiem. – skypjack

Odpowiedz

4

sugeruję następujące (ab) zastosowanie operatora przecinkami:

return (void)array, N; 
+1

W ramach tego pytania podoba mi się to, co najlepsze, ponieważ nie powinno się niczego oceniać. Prawdopodobnie warto dodać komentarz, taki jak '// void cast with operator przecinka dla kompatybilności C++ 11 ' – hyde

+0

@hyde yes, dokumentowanie (stosunkowo) dziwnego zwracanego wyrażenia z komentarzem jest prawdopodobnie dobrym pomysłem. –

2

Najlepszym rozwiązaniem jest ten, który jest zabroniony z drugim punktem, to znaczy z użyciem T(&)[N].

Innym możliwym podejściem, począwszy od komentarza, jest zastosowanie następujące wartości zwracanej:

return array ? N : N; 

jestem całkiem pewny, że kompilator będzie pozbyć się go i nie będzie problemu z wydajnością w środowisku wykonawczym .

+0

Jeśli chcesz wyłączyć ostrzeżenie kompilatora, użyj #pragma, aby go wyłączyć.Odwoływanie się do parametru bez przyczyny niż do zignorowania ostrzeżenia kompilatora jest przeciwieństwem pisania czytelnego kodu czytelnego. –

+1

Wolałbym umieścić jedyny typ bez nazwy zmiennej, który jest o wiele jaśniejszy niż pragma, ale ma pewne ograniczenia (zobacz pytanie), a ten jest możliwym i przenośnym rozwiązaniem, niczym więcej. – skypjack

4

Spróbuj tego. I skorzystać z tej metody czasami

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (& /*array*/)[N]) noexcept { return N; } 
+2

Czy przeczytałeś pytanie lub odpowiedź z @skypjack? –

+0

@ m.s. Tak, nie przeczytałem odpowiedzi do końca. Poprawię lub skasuję moją odpowiedź za dziesięć minut. – fnc12

+1

Najbardziej podoba mi się to rozwiązanie, ponieważ nie wprowadza żadnej niepotrzebnej logiki, która może wprowadzać czytelnika w błąd, tak jak inne odpowiedzi. – Sopel

1

jak @ fnc12 i @skypjack zarówno wskazują obecnie, idiomatyczne sposób uciszyć nieużywany parametr ostrzeżenie kompilatora jest nie nadać nazwę parametru.

constexpr std::size_t arraySize(T (& /*array*/)[N]) noexcept { return N; } 

Zastosowanie komentarzy rozwiązuje sprzeciw czytelności. Nie naprawia to nazwy w komunikacie kompilatora, ale twierdzę, że najbardziej prawdopodobną sytuacją jest "niezadeklarowany identyfikator", który jest dość łatwy i oczywisty do rozwiązania, gdy zauważysz, że identyfikator jest komentowany.

Jeśli naprawdę nie jesteś ustawiony w sposób idiomatyczny, po prostu pomiń ostrzeżenie (lokalnie, jeśli pozwala na to twój kompilator).

Suppressing warnings in GCC using #pragma GCC diagnostic.

Suppressing warnings in Visual Studio using #pragma warning suppress

ja odradzam dodawanie referencji „obojętne” w kodzie, aby zamknąć kompilatora. Odwoływanie się do nieużywanego parametru bez przyczyny, niż do stłumienia ostrzeżenia kompilatora, niepotrzebnie zwiększa złożoność kodu i może zmylić przyszłych opiekunów z tego powodu.

+1

W rzeczywistości, umieszczając nazwę parametru w komentarzach, przynajmniej * gcc * pokazuje to, więc to też pomaga (oczywiście wygląda trochę brzydko ...). Zdecydowanie zgadzam się z usunięciem nieużywanej nazwy parametru z funkcji * definition *. Jednak deklaracje IMO powinny je mieć, a tutaj definicja i deklaracja są takie same. – hyde

1

Unnamed argument jest dobrym rozwiązaniem.

Więc można użyć pośrednią funkcję:

template <typename T> 
constexpr void avoid_warning_for_unused_parameter(T&&) noexcept{} 

a następnie:

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept 
{ 
    avoid_warning_for_unused_parameter(array); 
    return N; 
} 

dla C++ 11, trzeba włamać trochę więcej:

template <typename... Ts> 
constexpr auto return_first_and_avoid_warning_for_unused_parameters(T&&t, Ts&&) noexcept 
-> decltype(t) 
{ 
    return t; 
} 

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept 
{ 
    return return_first_and_avoid_warning_for_unused_parameters(N, array); 
} 
+0

Nie różni się to zbytnio od używania tradycyjnej obsady '(void)', ponieważ to też * wymaga C++ 14 *. Rozumiem sens tworzenia wyraźnie nazwanej "nieużywanej" funkcji (lub makra), ale osobiście wolałbym zwykły, stary tradycyjny "(void)" rzucony na zagracenie dodatkowej funkcji, ponieważ jest to dość dobrze znany idiom. YMMV. – hyde

+1

@hyde: zgodnie z http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/, '(void) array' nie działa dla wszystkich kompilatorów. – Jarod42

+0

Interesująca dyskusja tam, dobrze wiedzieć! – hyde

1

gcc dostarcza unused attribute, który może być używany w następujący sposób:

constexpr std::size_t arraySize(__attribute__((unused)) T (&array)[N]) noexcept { return N; } 
           ^^^^^^^^^^^^^^^^^^^^^^^ 

Ben Deane recently tweatted about a C++11 way stłumić to ostrzeżenie za pomocą lambdy które w połączeniu z operatorem przecinkami będzie wyglądać mniej więcej tak:

#define UNUSED(x) [&x]{}() 

//... 

return UNUSED(array), N; 
2

Dla nowych pracowników Google:

C++ 17 dodaje atrybut, który mógłby [[maybe_unused]] używaj tak:

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }