2010-11-11 5 views
11

In Code zu aktivieren:Wie enable_if verwenden, um Elementfunktionen basierend auf Template-Parameter der Klasse

template<class T> 
struct is_builtin 
{ 
    enum {value = 0}; 
}; 

template<> 
struct is_builtin<char> 
{ 
    enum {value = 1}; 
}; 

template<> 
struct is_builtin<int> 
{ 
    enum {value = 1}; 
}; 

template<> 
struct is_builtin<double> 
{ 
    enum {value = 1}; 
}; 

template<class T> 
struct My 
{ 
    typename enable_if<is_builtin<T>::value,void>::type f(T arg) 
    { 
     std::cout << "Built-in as a param.\n"; 
    } 


    typename enable_if<!is_builtin<T>::value,void>::type f(T arg) 
    { 
     std::cout << "Non - built-in as a param.\n"; 
    } 
}; 

struct A 
{ 
}; 

int main() 
{ 
    A a; 
    My<int> m; 
    My<A> ma; 
    m.f(1); 
    ma.f(a); 
    return 0; 
} 

Ich erhalte eine Fehlermeldung:

error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'  

Offensichtlich verstehe ich nicht, wie zu bedienen enable_if. Was ich dachte war, dass ich während der Kompilierungszeit eine oder eine zweite Mitgliedsfunktion aus einer Reihe von Mitgliedsfunktionen aktivieren kann, aber es funktioniert nicht. Könnte mir bitte jemand erklären, wie man es richtig macht?
Bearbeitet
Was ich wirklich nicht verstehen kann ist, warum nicht typedef in einem dieser def. Compiler kann es nicht finden und wird es nicht kompilieren.

Antwort

13

Sie können keine Klassenvorlagenparameter verwenden, um SFINAE für Elementfunktionen zu erhalten.

müssen Sie entweder

  • die Member-Funktion stattdessen eine Memberfunktion Vorlage erstellen und verwenden enable_if auf der Member-Funktion Vorlage der Template-Parameter oder

  • Bewegung der Memberfunktion f in eine Policy-Klasse und Spezialisieren Sie die Klassenvorlage mit enable_if.

+0

Sie bitte einige Beispiele bieten könnte? –

+0

@There: Es gibt ein Beispiel für die Verwendung des zweiten Ansatzes (spezialisiert auf eine Klassenvorlage) in [der Boost 'enable_if' Dokumentation] (http://beta.boost.org/doc/libs/1_44_0/libs/utility/enable_if .html) (siehe Abschnitt 3.1). –

+0

danke für den link. Ich werde es jetzt lesen. –

-2

enable_if erwartet eine Metafunktion. Um einen Bool zu verwenden, benötigen Sie enable_if_c. Ich bin überrascht, dass Sie keine Fehler bekommen, die dieses Problem erklären.

Sie können Ihre Metafunktion reparieren, indem Sie einen typedef-Typ deklarieren, der einfach selbst ist. Dann können Sie boost::enable_if<is_builtin<T>>::type

+1

Ich benutze std :: enable_if –

0

Hier verwenden, wie es funktioniert (beachten Sie, dass die Einfachheit halber ersetzt ich Ihren is_builtin Zug mit std::is_arithmetic und weiteren C++ 11 Sachen verwendet, aber es funktioniert jede mögliche Weise):

template<class T> 
struct My 
{ 
    template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr> 
    void f(T_ arg) 
    { 
     std::cout << "Built-in as a param.\n"; 
    } 

    template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr> 
    void f(T_ arg) 
    { 
     std::cout << "Non - built-in as a param.\n"; 
    } 
}; 

DEMO

der entscheidende Teil ist die Template-Parameter in den unmittelbaren Kontext zu bringen durch einen Standard-Funktion Template-Parameter T_ verwendet, die die Klasse Template-Parameter gleich T. Weitere Informationen finden Sie unter this question.

1

Sie können den Code beheben, indem enable_if

template < typename T > 
struct __Conflict {}; 

template <bool B, class T = void> 
struct __enable_if { typedef __Conflict<T> type; }; 

template <class T> 
struct __enable_if<true, T> { typedef T type; }; 

Beispiel für die Verwendung modifiziert werden:

template <typename T> 
class Lazy 
{ 
public: 
    void _ctor(bool b); 
    void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type); 
}; 

template <typename T> 
void Lazy<T>::_ctor(bool b) 
{ 
    std::cout << "bool " << b << std::endl; 
}; 

template <typename T> 
void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t) 
{ 
    std::cout << "T " << t << std::endl; 
}; 

int main(int argc, char **argv) 
{ 
    Lazy<int> i; 
    i._ctor(10); 
    i._ctor(true); 

    Lazy<bool> b; 
    b._ctor(true); 

    return 0; 
} 
+0

+1, obwohl ich normalerweise versuche, Namen mit Unterstrichen zu vermeiden, weil es Regeln gibt, bei denen jeder Name, der mit einem oder zwei Unterstrichen beginnt, in einigen Fällen reserviert ist. Gibt es einen Grund, warum Sie eine Funktion '_ctor' benannt haben, anstatt nur einen Konstruktor zu definieren? – SirGuy

+0

Wie ich mich erinnere, werden Unterstreichungen verwendet, um die lokale Implementierung von etwas zu zeigen, _ctor ist nur Name der Methode in meinem Code, die ich nicht umständlich zu benennen – Alexander77

+0

Von [cppreference] (http://en.cppreference.com/w/ cpp/keyword): _Also, ** alle Bezeichner, die einen doppelten Unterstrich __ an einer beliebigen Position ** enthalten und jeder Bezeichner, der mit einem Unterstrich gefolgt von einem Großbuchstaben beginnt, ist immer reserviert und alle Bezeichner, die mit einem Unterstrich beginnen, sind reserviert Verwenden Sie als Namen im globalen Namespace. Weitere Details finden Sie unter Bezeichner._ Zumindest sollte Ihre '__enable_if'-Vorlage umbenannt werden, um sicherzustellen, dass sie die Standardimplementierung der Bibliothek nicht beeinträchtigt. – SirGuy