2016-01-08 11 views
10

C'è un modo per testare std::is_base_of<A, B> quando A è una classe template?std :: is_base_of per classi template

template <typename X, typename Y> class A {}; 

template <typename X> class B : public A<X, char> {}; 

voglio provare qualcosa di simile in modo statico, std::is_base_of<A, B<int>> significato, B è derivato da qualsiasi specializzazione del A. (Per renderlo più generale, diciamo che non sappiamo il modo B specializza A, vale a dire B <X> deriva da una < X, char >)

Un modo per risolvere sarebbe quello di un derivato da una classe (non modello) dire C, quindi controllare std::is_base_of<C, B<int>>. Ma c'è un altro modo per farlo?

+1

'A' non è un tipo. Non puoi farlo, ma puoi fare 'std :: is_base_of , B >' – Arunmu

+0

Tipo di domanda simile Ho risposto qualche tempo fa. http://stackoverflow.com/questions/34670375/how-to-enforce-template-parameter-class-to-derive-from-super-with-an-anonymous-t/34670684#34670684 – Arunmu

+0

Would 'my_is_base_of , char > 'essere un uso ragionevole per te? – TartanLlama

risposta

13

E 'possibile effettuare le seguenti operazioni:

template <template <typename...> class C, typename...Ts> 
std::true_type is_base_of_template_impl(const C<Ts...>*); 

template <template <typename...> class C> 
std::false_type is_base_of_template_impl(...); 

template <typename T, template <typename...> class C> 
using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T*>())); 

Live Demo

ma non riuscirà con multipla successione o privato eredità da A.

+1

Huh, non avevo idea che "Ts ..." potesse essere dedotto in quel contesto. Bello! – TartanLlama

+2

Sono arrivato alla stessa soluzione, ma questa soluzione anche __fails__ (piuttosto che restituisce 'false') con una singola ereditarietà non pubblica da' A' :( – mpark

+1

@ Jarod42: Grazie! È abbastanza intelligente. –

0

La seguente soluzione funziona con ereditarietà protetta.

template <template <typename...> class BaseTemplate, typename Derived, typename TCheck = void> 
struct test_base_template; 

template <template <typename...> class BaseTemplate, typename Derived> 
using is_base_template_of = typename test_base_template<BaseTemplate, Derived>::is_base; 

//Derive - is a class. Let inherit from Derive, so it can cast to its protected parents 
template <template <typename...> class BaseTemplate, typename Derived> 
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<std::is_class_v<Derived>>> : Derived 
{ 
    template<typename...T> 
    static constexpr std::true_type test(BaseTemplate<T...> *); 
    static constexpr std::false_type test(...); 
    using is_base = decltype(test((test_base_template *) nullptr)); 
}; 

//Derive - is not a class, so it is always false_type 
template <template <typename...> class BaseTemplate, typename Derived> 
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<!std::is_class_v<Derived>>> 
{ 
    using is_base = std::false_type; 
}; 

Sorprendentemente, il VS2017, funziona con l'ereditarietà multipla dallo stesso modello, come il C < int> e C < galleggiante> entrambi. (Non ho idea come!)

Controllare il Link to test code

Problemi correlati