2015-10-24 7 views
5

Vorrei verificare se due tipi sono uguali, ma indipendentemente dai parametri del modello. Qualcosa di simile a questo:Come verificare se due tipi provengono dalla stessa classe di modelli

template<class T> 
class A {}; 
class B {}; 

int main() { 
    cout << std::is_same_template<A<int>, A<string>>::value << endl; // true 
    cout << std::is_same_template<A<int>, B>::value << endl; // false 
} 

Sono consapevole std::is_same per verificare se due tipi di corrispondenza exacty.

Un motivo per cui ho bisogno di questo: Ho un metodo basato su modelli che può essere chiamato con qualsiasi tipo, ma vorrebbe impedire cioè viene chiamato con il tipo A (che è template), eventualmente utilizzando un static_assert. Sono stati A non su modelli, credo che potrebbe essere fatto facilmente usando std::is_same, ma ora, ho un problema ...

EDIT: posso escludere manualmente una per pochi comuni Ts, utilizzando, Cerco un modo di farlo per tutti i T:

static_assert(!std::is_same<parameter_type, A<int>>::value, "Cannot use this function with type A<T>"); 
static_assert(!std::is_same<parameter_type, A<double>>::value, "Cannot use this function with type A<T>"); 
static_assert(!std::is_same<parameter_type, A<bool>>::value, "Cannot use this function with type A<T>"); 
+0

Due tipi non sono gli stessi, se i loro parametri template sono diversi. Pertanto, 'A ' e 'A ' sono lontani dallo stesso tipo. – skypjack

+2

Bene, ne sono a conoscenza, ecco perché non posso usare 'std :: is_same'. Quello che sto chiedendo è, se c'è un modo per confrontare meno rigorosamente, rendere A confronta uguale e A e B no? – jureslak

+0

È possibile utilizzare l'approccio inverso mediante la specializzazione del modello, quindi accettare solo le classi consentite e definire altrimenti una funzione vuota/rotta/di lancio/qualsiasi. – skypjack

risposta

4

Okay, come su questo:

#include <iostream> 

template<class T> 
struct A {}; 
struct B {}; 

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

template <typename T> 
struct should_reject<A<T>> { static constexpr bool value = true; }; 

template <typename T> 
void rejectA(T t) 
{ 
    std::cout << should_reject<T>::value << std::endl; 
} 

int main() { 
    rejectA(B());   // false 
    rejectA(1);   // false 
    rejectA(1.0);   // false 
    rejectA(A<B>());  // true 
    rejectA(A<int>()); // true 
    rejectA(A<double>()); // true 
} 
+0

Vorrei che quei due esempi in voi fossero uguali, ma mi avete dato qualche idea. Potrei modificare per funzionare per rifiutare i tipi, che hanno un typdef cetain definito? O forse anche un valore di runtime ... (e il downvote non è mio) – jureslak

+0

Oh, ho completamente letto male la tua domanda. Perdonami per quello. –

+0

Ho modificato la mia risposta. –

3

mi è venuta in mente un modo più semplice di quello di @ NikitaKakuev risposta, attualmente utilizzato su un project of mine.

template<typename, typename> 
constexpr bool is_same_template{false}; 

template< 
    template<typename...> class T, //typename T in C++17 
    typename... A, 
    typename... B 
> 
constexpr bool is_same_template< 
    T<A...>, 
    T<B...> 
>{true}; 

L'unico problema attuale è con i modelli che combinano tipi e nomi di tipo, vale a dire. std::array<int, 10>.
Per superare questa limitazione, è necessaria la specializzazione.

Usage:

bool b = is_same_template<std::string, std::wstring>; //true 
//both are typedefs of std::basic_string 

EDIT: Come richiesto dal @Helix nel commento qui sotto, specializzazione per std::array (o di qualsiasi altro modello con la stessa firma):

template< 
    template<typename, std::size_t> class T, //typename T in C++17 
    typename TA, std::size_t NA, 
    typename TB, std::size_t NB 
> 
constexpr bool is_same_template< 
    T<TA, NA>, 
    T<TB, NB> 
>{true}; 
+0

Ehi, mi stavo chiedendo se potevi aggiornare la tua risposta per includere un esempio di quella specializzazione? – FrogTheFrog

+1

@Helix ecco qua. – bit2shift

Problemi correlati