Jak sprawdzić typ parametru szablonu?

97

Załóżmy, że mam funkcję szablonu i dwie klasy

class animal {
}
class person {
}

template<class T>
void foo() {
  if (T is animal) {
    kill();
  }
}

Jak sprawdzić, czy T to zwierzę? Nie chcę mieć czegoś, co sprawdza się w czasie wykonywania. Dzięki

WhatABeautifulWorld
źródło
62
Wpisałbym

Odpowiedzi:

135

Zastosowanie is_same:

#include <type_traits>

template <typename T>
void foo()
{
    if (std::is_same<T, animal>::value) { /* ... */ }  // optimizable...
}

Zwykle jest to jednak całkowicie niewykonalny projekt i naprawdę chcesz się specjalizować :

template <typename T> void foo() { /* generic implementation  */ }

template <> void foo<animal>()   { /* specific for T = animal */ }

Zauważ również, że nietypowe jest posiadanie szablonów funkcji z jawnymi (niewyprowadzonymi) argumentami. Nie jest to niespotykane, ale często istnieją lepsze podejścia.

Kerrek SB
źródło
2
Dzięki! Właściwie udostępniają DUŻO kodu, więc nie mogę go tak naprawdę powielić
WhatABeautifulWorld
3
@WhatABeautifulWorld: Zawsze możesz wziąć pod uwagę swój kod, aby część zależna od typu mogła zostać zdegradowana do funkcji specjalizowanej ...
Kerrek SB
1
Jedna szybka kontynuacja, jeśli użyję std :: is_same, to NIE spowolni to kodu dla innych parametrów szablonu, prawda?
WhatABeautifulWorld
1
@WhatABeautifulWorld: wszystkie wartości cech są znane statycznie. Nie powinno być żadnych kosztów wykonania, pod warunkiem, że Twój kompilator jest w połowie przyzwoity. Jeśli jednak masz wątpliwości, sprawdź zespół.
Kerrek SB
2
@ AdriC.S .: Ponieważ Tnie jest to wydedukowane, niewiele można zrobić. Możesz pozostawić podstawowy szablon niezaimplementowany i utworzyć specjalizację lub możesz dodać statyczne potwierdzenie za pomocą is_same.
Kerrek SB
37

Myślę, że dziś lepiej jest używać, ale tylko z C ++ 17.

#include <type_traits>

template <typename T>
void foo() {
    if constexpr (std::is_same_v<T, animal>) {
        // use type specific operations... 
    } 
}

Jeśli użyjesz operacji specyficznych dla typu w treści wyrażenia if bez constexpr, ten kod nie zostanie skompilowany.

Константин Гудков
źródło
8
zamiast std::is_same<T, U>::valueciebie możesz użyć krótszego:std::is_same_v<T, U>
Fureeish
12

W C ++ 17 możemy używać wariantów .

Aby użyć std::variant, musisz dołączyć nagłówek:

#include <variant>

Następnie możesz dodać std::variantswój kod w następujący sposób:

using Type = std::variant<Animal, Person>;

template <class T>
void foo(Type type) {
    if (std::is_same_v<type, Animal>) {
        // Do stuff...
    } else {
        // Do stuff...
    }
}
Edwin Pratt
źródło
8
Jak połączone są T i Type?
mabraham
4
Ta odpowiedź jest problematyczna z kilku powodów. Poza faktycznymi błędami ( typektóre są wartością typu Typelub szablonem, który nie ma tu sensu) is_same_vnie ma znaczenia w kontekście variant. Odpowiednią „cechą” jest holds_alternative.
Pixelchemist
std::variantjest tu zupełnie niepotrzebne
tjysdsg
7

Możesz specjalizować swoje szablony na podstawie tego, co jest przekazywane do ich parametrów, w następujący sposób:

template <> void foo<animal> {

}

Zauważ, że tworzy to całkowicie nową funkcję na podstawie typu przekazanego jako T. Zwykle jest to preferowane, ponieważ zmniejsza bałagan i jest przede wszystkim powodem, dla którego mamy szablony na pierwszym miejscu.

szablon chłopiec
źródło
Hmm. Czy ta metoda jest rzeczywiście jedynym preferowanym sposobem specjalizacji argumentów szablonu? Powiedzmy, że mam 10 różnych klas podrzędnych, którymi muszę zarządzać w funkcji szablonu. Czy naprawdę muszę napisać 10 różnych funkcji szablonów dla odpowiedniej klasy? Myślę, że brakuje mi tutaj sedna.
Volkan Güven
To naprawdę brzmi jak dobry pomysł, jeśli ktoś nie chce używać type_traits. Jak ktoś wspomniał, główną logikę można wykonać w innej funkcji, która akceptuje dodatkową flagę wskazującą typ, a ta wyspecjalizowana deklaracja może po prostu odpowiednio ustawić flagę i bezpośrednio przekazać wszystkie inne argumenty bez dotykania czegokolwiek. Więc jeśli trzeba obsłużyć 10 różnych klas, jest to w zasadzie 10 wierszy na 10 różnych definicji funkcji. Ale stanie się to bardzo skomplikowane, jeśli istnieje więcej niż 1 zmienna szablonu.
Harish Ganesan