2012-08-29 5 views
6

Come testare in fase di compilazione se la classe B è derivata da std :: vector?Come verificare se la classe B è derivata dalla famiglia di classi di template

template<class A> 
struct is_derived_from_vector { 
    static const bool value = ????; 
}; 

Come verificare in fase di compilazione se la classe B è derivata dalla famiglia di modelli?

template<class A, template<class> class Family> 
struct is_derived_from_template { 
    static const bool value = ????; 
}; 

Usando:

template<class T> struct X {}; 

struct A : X<int> {} 
struct B : std::vector<char> {} 
struct D : X<D> {} 

int main() { 
    std::cout << is_derived_from_template<A, X>::value << std::endl; // true 
    std::cout << is_derived_from_template<D, X>::value << std::endl; // true 
    std::cout << is_derived_from_vector<A>::value << std::endl; // false 
    std::cout << is_derived_from_vector<B>::value << std::endl; // true 
} 
+4

Con modello metaprogrammazione, è importante per rendere più esplicita se avete bisogno di un C++ 03 solo o con una soluzione C++ 11 è buono (anche se non sono sicuro che il C++ 11 può aiutare qui) . E come osservazione intelligente, dato che non si dovrebbe mai ereditare da contenitori standard il tratto originale è semplice: 'false': P –

+0

C++ 03. Io uso il compilatore msvc 2010. Pertanto accetto di usare 'decltype' in aggiunta. 'std :: vector' è per esempio ony. Se non conosci la soluzione C++ 03, allora anche la soluzione C++ 11 è la benvenuta. –

risposta

12

Prova questa:

#include <type_traits> 

template <typename T, template <typename> class Tmpl> // #1 see note 
struct is_derived 
{ 
    typedef char yes[1]; 
    typedef char no[2]; 

    static no & test(...); 

    template <typename U> 
    static yes & test(Tmpl<U> const &); 

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes); 
}; 

Usage:

#include <iostream> 

template<class T> struct X {}; 

struct A : X<int> {}; 

int main() 
{ 
    std::cout << is_derived<A, X>::value << std::endl; 
    std::cout << is_derived<int, X>::value << std::endl; 
} 

Nota: Nella riga contrassegnato #1, si potrebbe anche rendere il vostro tratto accettare qualsiasi modello che ha almeno uno, ma forse più argomenti di tipo da writint:

template <typename, typename...> class Tmpl 
+0

Se si utilizza 'modello classe Tmpl' e si utilizza un pacchetto di parametri per la funzione di test, si dovrebbe anche essere in grado di gestire un modello con un numero qualsiasi di argomenti, non solo uno. –

+1

Il problema con questo approccio è che funzionerà solo per i modelli con un singolo argomento. Anche se lo si aumenta per prendere i * soliti * due argomenti di 'std :: vector', l'implementazione può aggiungere parametri di template aggiuntivi (purché fornisca valori predefiniti per quei parametri), quindi non sarà 100% portatile –

+1

@ DavidRodríguez-dribeas: Sì, rendilo vario ... –

1

ho avuto la stessa situazione che avevo bisogno di sapere se una classe è derivata da un vettore (come)-classe. Sfortunatamente non ci sono macro C++ - 11 o variadic consentite nel mio progetto. Quindi la mia soluzione era un misto di Kerrek's answer e questo article con qualche googletest-codice alla fine:

#include <vector> 

template <typename T> 
class is_derived_from_vector 
{ 
    typedef char Yes_t[1]; 
    typedef char No_t[2]; 

    static No_t& test(const void* const); 

    template <typename U> 
    static Yes_t& test(const std::vector<U>* const); 

public: 
    static const bool value = ((sizeof(test(static_cast<T*>(0)))) == (sizeof(Yes_t))); 
}; 

template<class T> struct X {}; 
struct A : X<int> {}; 
struct B : std::vector<char> {}; 

TEST(Example, IsDerivedFrom) 
{ 
    EXPECT_FALSE(is_derived_from_vector<A>::value); 
    EXPECT_TRUE(is_derived_from_vector<B>::value); 
} 

una soluzione comune per tutti i modelli Credo che non sarebbe possibile definire, senza l'utilizzo di C++ - 11 o superiore.

0

ero alla ricerca di una soluzione a questo problema non molto tempo fa e dopo aver consultato

moderni C design ++: programmazione generica e Design Patterns applicata

sono stato in grado di costruire il seguito della quale è più o meno simile a ciò che è stato fornito nei commenti.

#include <iostream> 
#include <type_traits> 
#include <utility> 

template <typename T, template <typename...> class U> 
struct is_derived 
{ 
private: 
    template <typename...Ts> 
    static constexpr std::true_type check(const U<Ts...>&); 
    static constexpr std::false_type check(...); 


    template <typename> 
    struct is_same 
    { 
     static constexpr bool value = false; 
    }; 

    template <typename...Ts> 
    struct is_same <U<Ts...>> 
    { 
     static constexpr bool value = true; 
    }; 

    public: 
    static constexpr bool value = 
     std::is_same<decltype(check(std::declval<T>())), 
        std::true_type>::value && 
     !is_same<T>::value; 
}; 

template <typename, typename> 
struct X 
{ 
}; 

template <typename T> 
struct Y : X <T, int> 
{ 
}; 


int main(int argc, char **argv) { 

    std::cout << std::boolalpha << is_derived<Y<int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<X<int,int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<int, X>::value << std::endl; 

    return 0; 
} 
Problemi correlati