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


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.


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.


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...
    }
}

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.