2013-05-02 8 views
10

Sono stato su questo problema per tutta la mattinata senza alcun risultato. Fondamentalmente, ho bisogno di una semplice metaprogrammazione che mi permetta di diramarti verso diverse specializzazioni se il parametro passato è una specie di std :: vector o meno.Come sapere se un tipo è una specializzazione di std :: vector?

Alcuni tipi di is_base_of per i modelli.

Esiste una cosa del genere?

+0

Con "specializzazione" intendi eredità? O un alias di tipo (ad esempio 'typedef')? O un'implementazione specializzata per un certo tipo (come 'std :: vector ' is)? –

+1

La tua domanda è vaga: se vuoi determinare se un tipo è una specializzazione template di 'std :: vector' per un tipo, non dovresti riuscire a farlo (non in modo pulito comunque). Se vuoi determinare se un tipo è ereditato da std :: vector , questo è esplicitamente sconsigliato (std :: vector non ha un distruttore virtuale e NON DEVE essere ereditato, solo incapsulato). Se vuoi determinare se un parametro class/typedef/template è un std :: vector , dovresti usare una classe di caratteri basata su modelli (vedi risposta da jrok). – utnapistim

+0

@utnapistim: Non è * difficile * verificare se un tipo è una specializzazione di un modello in generale. –

risposta

12

In C++ 11 si può anche fare in modo più generico:

#include <type_traits> 
#include <iostream> 

template<typename Test, template<typename...> class Ref> 
struct is_specialization : std::false_type {}; 

template<template<typename...> class Ref, typename... Args> 
struct is_specialization<Ref<Args...>, Ref>: std::true_type {}; 


int main() 
{ 
    typedef std::vector<int> vec; 
    typedef int not_vec; 
    std::cout << is_specialization<vec, std::vector>::value << is_specialization<not_vec, std::vector>::value; 

    typedef std::list<int> lst; 
    typedef int not_lst; 
    std::cout << is_specialization<lst, std::list>::value << is_specialization<not_lst, std::list>::value; 
} 
+0

Wow, fratello così dolce! – Michael

+0

Ciao! In che modo questo esempio può essere modificato per supportare anche std :: array che ha un parametro template non di tipo? –

+0

No, non la penso così. È perché non esiste un meccanismo generico che sia un typename o un valore-type e possa contenere un tipo o un valore concreto. Scusa, penso che tu debba scrivere un modello speciale is_std_array. – Databyte

3

No, ma è possibile sovraccaricare con una funzione modello che accetta solo std::vector<T>. Il compilatore sceglierà il modello più specializzato in questi casi.

15

Se avete bisogno di una classe tratto è abbastanza semplice, è necessario solo un modello generale e una specializzazione da qualsiasi std::vector:

#include <type_traits> 
#include <iostream> 

template<typename> 
struct is_std_vector : std::false_type {}; 

template<typename T, typename A> 
struct is_std_vector<std::vector<T,A>> : std::true_type {}; 

int main() 
{ 
    typedef std::vector<int> vec; 
    typedef int not_vec; 
    std::cout << is_std_vector<vec>::value << is_std_vector<not_vec>::value; 
} 
+5

Per essere completo, è necessario specializzarsi per 'vector ' per catturare anche i vettori con gli allocatori personalizzati. – dhavenith

+0

@dhavenith assolutamente corretto, grazie per averlo fatto notare. – jrok

+1

Nota: le implementazioni possono aggiungere ulteriori argomenti del modello, quindi potresti voler controllare. Sebbene il codice precedente rileverà ogni istanza del vettore che utilizza i valori predefiniti per i possibili parametri aggiuntivi del modello. –

Problemi correlati