2012-06-02 14 views
6

che sto cercando di scrivere terzi modelli funzione operatore come:Come si usa enable_if per i modelli di funzione non membri mutuamente esclusivi?

#include <utility> 

template < typename T, unsigned L > 
class MyType; 

template < typename T, typename U, unsigned L > 
auto operator ==(MyType<T,L> const &l, MyType<U,L> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

Ma quando provo a gestire quando l e r hanno lunghezze diverse:

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt < Lu)>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt > Lu)>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

ricevo errori ambiguità. Ho provato qualcosa del tipo:

template < typename T, unsigned Lt, typename U, unsigned Lu, bool B = (Lt < Lu), class Enable = typename std::enable_if<B>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

template < typename T, unsigned Lt, typename U, unsigned Lu, bool B = (Lt > Lu), class Enable = typename std::enable_if<B>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

che ho letto (qui su S.O.) per risolvere problemi come questo per i modelli di funzioni membro. (A volte, i rispondenti hanno cambiato una funzione membro in un modello funzione membro per abilitarlo.) Ma gli errori non cambiano per me. Devo passare a inserire enable_if nel tipo restituito?

Oh, l'espressione del tipo restituito dovrebbe escludere questo operatore quando i due tipi di elementi non possono essere confrontati. Funzionerà davvero? È compatibile con l'installazione di enable_if?

+1

Che cos'è esattamente l'errore di ambiguità? –

risposta

11

È interessante notare che un certain fellow here on SO ha scritto un blogpost poco tempo fa, mostrando una bella tecnica SFINAE in stile C++ 11 che consente facilmente funzioni sovraccariche. La tecnica e la spiegazione sono fornite here.

In breve, il codice fallisce perché entrambi i modelli, quando analizzato per la prima volta e quando le dichiarazioni non dipendenti sono stati risolti, sono esattamente stesso, tipo-saggio. Come per gli argomenti delle funzioni predefinite, gli argomenti dei modelli predefiniti vengono sostituiti solo quando viene effettivamente chiamata la funzione. Questo è ciò che entrambi i modelli assomigliano al compilatore al momento della dichiarazione:

template<class T, unsigned Lt, class U, unsigned Lu, class Enable> 
auto operator==(MyType<T,Lt> const& l, MyType<U,Lu> const& r); 

Il seguente codice dovrebbe ottenere quello che vuoi:

namespace detail{ 
enum class enabler{}; 
} 

template<bool B, class T = detail::enabler> 
using EnableIf = typename std::enable_if<B, T>::type; 

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt < Lu)>...> 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt > Lu)>...> 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

Una domanda rimane, però ... cosa dovrebbe accadere se Lt == Lu? In tal caso, nessun sovraccarico è praticabile.

+0

Wow! La mia mente è esplosa. Avevo pensato alla multi-condizione (abbastanza facile con variadic), ma ... combinando così tante tecniche e riuscendo a raggiungere un punto così sintattico. Stupefacente. Grazie per aver condiviso l'articolo. –

+0

La versione di 'operator ==' nel primo blocco copre il caso in cui i secondi parametri del modello di classe sono uguali. Le due versioni di cui sto chiedendo si aggiungono alla prima versione e non la sostituiscono. – CTMacUser

+0

Questo è un articolo * molto * interessante. Per il mio codice, ho usato 'typename std :: enable_if :: type ...' come parametro finale del template. Il mio compilatore, GCC-4.7 (32-bit PowerPC, da MacPorts), ha accettato tale parametro, anche se tecnicamente è "vuoto ..." (un tipo incompleto) e l'articolo diceva che "void" non poteva essere usato! Stavo pensando di usare 'std :: nullptr_t' o' int' dato che non volevo aggiungere un tipo di throwaway al codice della libreria (ma, non importa). – CTMacUser

Problemi correlati