2012-08-17 10 views
6

Ho il seguente codice che non viene compilato. Questo sono due funzioni in una classe template che prende gli argomentiMetodo template enable_if specializzazione

typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // ... 
} 

typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // .... 
} 

voglio avere una specializzazione in un metodo membro a seconda del tipo Ret è.

Qualcuno ha qualche idea?

risposta

7

SFINAE non funziona su funzioni non modello (membro o non membro).

Come sottolinea Kerrek SB, far funzionare i modelli di funzioni non membri. O come indicato da Xeo, anche i template delle funzioni membro con un argomento template predefinito funzioneranno.

Tuttavia, questo funziona solo perché le due condizioni sono std::enable_ifnon sovrapposti. Se si desidera aggiungere un sovraccarico diverso per int (ad esempio), si scoprirà che non viene ridimensionato in modo corretto. A seconda di cosa si vuole fare, tag di dispacciamento in genere scale meglio di SFINAE con molteplici alternative che si desidera inviare a:

#include<type_traits> 

template<typename Ret> 
class Foo 
{ 
public: 
    void _on_dispatched() 
    { 
     // tag dispachting: create dummy of either std::false_type or std::true_type 
     // almost guaranteed to be optimized away by a decent compiler 
     helper_on_dispatched(std::is_void<Ret>()); 
    } 

private: 
    void helper_on_dispatched(std::false_type) 
    { 
     // do stuff for non-void 
    } 

    void helper_on_dispatched(std::true_type) 
    { 
     // do stuff for void 
    } 
}; 

int main() 
{ 
    Foo<void>()._on_dispatched(); 
    Foo<int>()._on_dispatched(); 
    return 0; 
} 
+1

È possibile, se uno dei sovraccarichi è l'unica percorribile in fase di chiamata. :) http://liveworkspace.org/code/fd6e5383610d4e0d8fb17c5497991355 – Xeo

+1

@Potatoswatter: In realtà no, non era uno scherzo. Vedi il link, puoi perfettamente avere una funzione con esattamente la stessa firma dove solo il tipo di ritorno decide se è valido. : P Inoltre, usa semplicemente 'std :: is_void ()', i caratteri di tipo sono necessari per derivare da 'std :: true_type' o' std :: false_type'. – Xeo

+1

Btw, [puoi semplicemente rendere il membro un modello con un parametro predefinito in C++ 11] (http://liveworkspace.org/code/781d94df5499998947217970c1aebf2a). – Xeo

3

SFINAE funziona solo su modelli. Il tuo codice può essere fatto per compilare con una piccola modifica:

template <typename Ret> 
typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

template <typename Ret> 
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

Usage:

auto q = _on_dispatched<int>(); 

È possibile, naturalmente, non dedurre il tipo di ritorno di una funzione, dal momento che non è deducibile. Tuttavia, è possibile confezionare questo modello all'interno un altro modello:

template <typename T> 
struct Foo 
{ 
    // insert templates here, maybe privately so 

    T bar() { return _on_dispatched<T>(); } 
}; 
+0

'template ' per le funzioni membro, vedere il mio commento sulla risposta di rhalbersma. – Xeo

+0

@Xeo: Vuoi dire che ci salverebbe dal dover scrivere ''? Certo, perché no :-) –