2015-03-07 17 views
9

Esiste un modo per creare una copia completa di un tipo in modo che possano essere distinti nel contesto di deduzione del modello? Prendiamo l'esempio:Strong typedef

#include <iostream> 

template <typename T> 
struct test 
{ 
    static int c() 
    { 
     static int t = 0; 
     return t++; 
    } 
}; 

typedef int handle; 

int main() 
{ 
    std::cout << test<int>::c() << std::endl; 
    std::cout << test<handle>::c() << std::endl; 
    return 0; 
} 

Dal typedef fa solo un alias per un tipo, questo stampa 0, 1 invece del desiderato 0, 0. C'è qualche soluzione per questo?

+1

Dai un'occhiata a [Boost strong typedef] (http://www.boost.org/doc/libs/1_57_0/libs/serialization/doc/strong_typedef.html). – interjay

risposta

6

Citando cplusplus.com,

Nota che né typedef né l'utilizzo di creare nuovi tipi di dati distinti. Creano solo sinonimi di tipi esistenti. Ciò significa che il tipo di myword precedente, dichiarato con tipo WORD, può anche essere considerato di tipo unsigned int; non importa, dal momento che entrambi sono in realtà riferiti allo stesso tipo.

Da int e handle are uno stesso, è prevista l'uscita 0 1.

C'è una soluzione, però, come suggerisce @interjay.

È possibile utilizzare BOOST_STRONG_TYPEDEF.

BOOST_STRONG_TYPEDEF(int , handle); 
+2

La domanda è trovare un'alternativa a 'typedef' che non avrà questo comportamento. – interjay

+0

Non penso ci sia un'alternativa a 'typedef', questo è il punto che sto cercando di evidenziare. – shauryachats

+2

Non ce n'è uno incorporato nella lingua, ma ciò non significa che non si possa costruire uno (ad esempio il link che ho postato sopra). – interjay

6

Seguendo l'idea di BOOST_STRONG_TYPEDEF, sono riuscito a trovare una soluzione generalizzata l'utilizzo delle macro, specializzazioni del modello e creazione di nome lambda automatica:

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

#define STRONG_TYPEDEF(target_type, new_type) \ 
    auto name_seed_##new_type = [](){}; \ 
    using new_type = strong_typedef<target_type, decltype(name_seed_##new_type)>; 

template <typename T, typename NameSeed, 
         typename Enable = typename std::conditional<!std::is_fundamental<T>::value, 
            std::true_type, 
            std::false_type>::type> 
struct strong_typedef; 

//specialization for non fundamental types 
template <typename T, typename NameSeed> 
struct strong_typedef<T, NameSeed, std::true_type> : public T 
{ 
    template <typename... Args> 
    strong_typedef(Args&&... args) : T(std::forward<Args>(args)...) {} 
}; 

//specialization for fundamental types 
template <typename T, typename NameSeed> 
struct strong_typedef<T, NameSeed, std::false_type> 
{               
    T t;               
    strong_typedef(const T t_) : t(t_) {};   
    strong_typedef(){};           
    strong_typedef(const strong_typedef & t_) : t(t_.t){}         
    strong_typedef & operator=(const strong_typedef & rhs) { t = rhs.t; return *this;}  
    strong_typedef & operator=(const T & rhs) { t = rhs; return *this;}  
    /*operator const T &() const {return t; }*/     
    operator T &() { return t; }        
    bool operator==(const strong_typedef & rhs) const { return t == rhs.t; } 
    bool operator<(const strong_typedef & rhs) const { return t < rhs.t; } 
}; 

template <typename> 
struct test 
{ 
    static int c() 
    { 
     static int t = 0; 
     return t++; 
    } 
}; 

struct A { int value; }; 

STRONG_TYPEDEF(A, B) 
STRONG_TYPEDEF(A, C) 
STRONG_TYPEDEF(int, D) 
STRONG_TYPEDEF(int, E) 

int main() 
{ 
    std::cout << test<A>::c() << std::endl; 
    std::cout << test<B>::c() << std::endl; 
    std::cout << test<C>::c() << std::endl; 
    std::cout << test<int>::c() << std::endl; 
    std::cout << test<D>::c() << std::endl; 
    std::cout << test<E>::c() << std::endl; 


    B t1; 
    C t2; 

    t1.value = 1; 
    t2.value = 2; 

    D t3(3); 
    E t4(4); 

    std::cout << t1.value << " " << t2.value << " " << t3 << " " << t4 << std::endl; 

    return 0; 
} 

Non è una soluzione molto IDE-friendly, ma funziona.

+0

Un chiaro sforzo che hai dimostrato dalla mia risposta sopra. +1 :) – shauryachats

+0

Puoi fornire maggiori dettagli sui tuoi commenti alla risposta precedente? Soprattutto cosa intendi per "Non funziona per i tipi definiti dall'utente" e "più typedef della stessa primitiva non si distinguono nelle deduzioni del modello". In quest'ultimo caso, come hai affrontato il problema? TIA! – akim

+0

Super tardi alla festa, ma temo che questi generati lambda globali [si romperanno] (https://stackoverflow.com/questions/18113164/lambda-in-header-file-error) se condividi i forti typedef attraverso unità di traduzione. – Quentin

2

Sia come suggerito BOOST_STRONG_TYPEDEF

template<typename> 
struct test { 
    static int c() { 
     static int t = 0; 
     return t++ ; 
    } 
}; 

//Instead of 
//typedef int handle 

BOOST_STRONG_TYPEDEF(int , handle) ; 

int main() { 

    std::cout << test<int>::c() << std::endl 
    std::cout << test<handle>::c() << std::endl ; 
    return 0; 
} 

uscita: 0 0, perché la maniglia è non int, ma un tipo implicitamente convertibile in int.

se non si desidera utilizzare BOOST_STRONG_TYPE poi semplicemente aggiungere secondo parametro al vostro modello di classe: fare

template<typename, unsigned int N> 
struct test { 
    static int c() { 
     static int t = 0; 
     return t++ ; 
    } 

}; 

Così test<int, 0> e test<handle, 1> tipi diversi

int main() { 

    std::cout << test<int, 0>::c() << std::endl ; 
    std::cout << test<handle,1>::c() << std::endl ; 
    return 0; 
} 

uscita: 0 0

È anche possibile aggiungere macro per generare i tipi:

#define DEFINE_TEST_TYPE(type) \ 
typedef test<type, __COUNTER__> test_##type; 


template<typename, unsigned int N> 
struct test {  
    static int c() { 
     static int t = 0; 
     return t++ ; 
    } 
}; 

typedef int handle ; 

DEFINE_TEST_TYPE(int) ; 
DEFINE_TEST_TYPE(handle) ; 

int main() { 
    std::cout << test_int::c() << std::endl ; 
    std::cout << test_handle::c() << std::endl ; 
    return 0; 
} 
+0

Per quanto riguarda la tua domanda ormai cancellata per il tuo progetto open source, potresti chiederlo alle community di Reddit pertinenti. Se lo chiedi in più di un sub, assicurati di dichiarare il tuo cross-post, in modo che le persone possano evitare di fare risposte doppie. – halfer