Come verificare il tipo di un parametro del modello?


95

Supponiamo che io abbia una funzione template e due classi

class animal {
}
class person {
}

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

Come faccio a verificare se T is animal? Non voglio avere qualcosa che controlli durante il tempo di esecuzione. Grazie


58

Risposte:


132

Usa is_same:

#include <type_traits>

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

Di solito, è un design totalmente impraticabile, però, e vuoi davvero specializzarti :

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

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

Nota anche che è insolito avere modelli di funzioni con argomenti espliciti (non dedotti). Non è inaudito, ma spesso ci sono approcci migliori.


2
Grazie! In realtà condividono
MOLTO

3
@WhatABeautifulWorld: puoi sempre fattorizzare il tuo codice in modo che la parte dipendente dal tipo possa essere relegata a una funzione specializzabile ...
Kerrek SB

1
Un rapido follow-up, se uso std :: is_same, NON rallenterà il codice per altri parametri del modello, giusto?
WhatABeautifulWorld

1
@WhatABeautifulWorld: i valori dei tratti sono tutti staticamente noti. Non dovrebbe esserci alcun costo di runtime, a condizione che il compilatore sia decente. In caso di dubbio, controlla l'assieme.
Kerrek SB

2
@ AdriC.S .: Dato che Tnon si deduce, non c'è molto che puoi fare. Puoi lasciare il modello principale non implementato e creare una specializzazione, oppure puoi aggiungere un'asserzione statica con is_same.
Kerrek SB

35

Penso che oggi sia meglio usare, ma solo con C ++ 17.

#include <type_traits>

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

Se si utilizzano alcune operazioni specifiche del tipo nel corpo dell'espressione if senza constexpr, questo codice non verrà compilato.


8
invece di std::is_same<T, U>::valuepotresti usare più brevi:std::is_same_v<T, U>
Fureeish

9

In C ++ 17 possiamo usare varianti .

Per utilizzarlo std::variant, devi includere l'intestazione:

#include <variant>

Successivamente, puoi aggiungere il std::varianttuo codice in questo modo:

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
Come sono collegati T e Type?
mabraham

4
Questa risposta è problematica in diversi modi. Inoltre gli errori effettivi ( typeche è il valore del tipo Typeo un modello che non ha senso qui) is_same_vnon è significativo nel contesto di variant. Il "tratto" corrispondente è holds_alternative.
Pixelchemist

std::variantè totalmente inutile qui
tjysdsg

7

Puoi specializzare i tuoi modelli in base a ciò che viene passato nei loro parametri in questo modo:

template <> void foo<animal> {

}

Nota che questo crea una funzione completamente nuova basata sul tipo passato come T. Questo di solito è preferibile in quanto riduce il disordine ed è essenzialmente il motivo per cui abbiamo i modelli in primo luogo.


Hmm. Questo metodo è davvero l'unico modo preferibile per specializzare l'argomento del modello? Diciamo che ho 10 classi figlie diverse che devo gestire all'interno della funzione template. Devo davvero scrivere 10 diverse funzioni modello per la rispettiva classe? Penso che potrebbe mancare il punto centrale qui.
Volkan Güven

Questa suona davvero come una buona idea, se qualcuno non vuole usare type_traits. Come qualcuno ha menzionato, la logica principale può essere eseguita in una funzione diversa, che accetta un flag aggiuntivo per indicare il tipo, e questa dichiarazione specializzata può semplicemente impostare il flag di conseguenza e passare direttamente tutti gli altri argomenti senza toccare nulla. Quindi, se è necessario gestire 10 classi diverse, si tratta fondamentalmente di 10 righe per 10 diverse definizioni di funzione. Ma questo diventerà molto complicato se ci sono più di 1 variabile di modello.
Harish Ganesan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.