2013-05-24 13 views
5

Ich versuche, einige SFINAE in einer Templatestruktur zu verwenden. Ich mein Problem auf folgendes reduziert und diese Arbeit machen könnte:Ungültige Verwendung des unvollständigen Typs (SFINAE)

template<bool mybool> 
struct test { 
    void myfunc(); 
}; 

template<bool mybool> 
void test<mybool>::myfunc() { 
    std::cout << "test true" << std::endl; 
} 
template<> 
void test<false>::myfunc() { 
    std::cout << "test false" << std::endl; 
} 

int main(int argc, char ** argv) { 
    test<true> foo; 
    test<false> bar; 
    foo.myfunc(); 
    bar.myfunc(); 
} 

Mit diesem Code, erhalte ich das Ergebnis:

test true 
test false 

Allerdings, wenn ich, dass meine struct test mit mehr als einem betrachten will Template-Parameter, habe ich versucht, die obigen wie folgt:

Ich bekomme eine ungültige Verwendung von unvollständigen Typ 'Struct Test'.

Gehe ich in die falsche Richtung? Gibt es eine Möglichkeit zu tun, was ich tun möchte? Danke für Ihre Hilfe!

+0

Haben Sie 'foo.myfunc bedeuten()', wenn Sie 'foo.test()' geschrieben hat? – bitmask

+0

Sie haben "myfunc" im zweiten Beispiel falsch geschrieben. Es sollte 'my_func' sein. Bitte versuchen Sie Ihre Beispiele, bevor Sie sie veröffentlichen. – pmr

Antwort

6

Sie können nicht Teilfunktion spezialisieren, sollten Sie partially specialize vollständige Struktur. Das folgende Beispiel funktioniert richtig

template<int myint, bool mybool> 
struct test { 
    void my_func(); 
}; 

template<int myint, bool mybool> 
void test<myint,mybool>::my_func() { 
    std::cout << "test true" << std::endl; 
} 

template<int myint> 
struct test<myint, false> { 
    void my_func(); 
}; 

template<int myint> 
void test<myint,false>::my_func() { 
//error: invalid use of incomplete type 'struct test<myint, false>' 
    std::cout << "test false" << std::endl; 
} 

int main(int argc, char ** argv) { 
    test<1,true> foo; 
    test<1,false> bar; 
    foo.my_func(); 
    bar.my_func(); 
} 
+0

Ok, habe deine Lösung ausprobiert und es hat Arbeit gekostet. Nehmen wir an, ich habe eine Menge Attribute in meiner Klasse, ich möchte sie wirklich nicht in beiden Strukturen deklarieren. Aber wenn ich sie nur in der ersten erkläre, kann ich nicht auf die spezialisierte zugreifen. Gibt es eine Möglichkeit für mich, die Erklärung von allem nicht zu verdoppeln? – Kiplaki

+1

@Kiplaki Ja, verwende einen Basis/Merkmalstyp. – ForEveR

+0

@Kiplaki Oder senden Sie eine Überladung mit 'false_type/true_type'. – pmr

3

Wenn Sie Ihre Klasse vermeiden wollen neu zu definieren, was würden Sie tun müssen, da teilweise Spezialisierung von (Mitglied) Funktionen nicht erlaubt ist, können Sie Ihre Art zersetzen könnten. Dies wird die Wiederholung des Codes minimieren:

template<int myint, bool mybool> 
struct test { 
    char some_var; 
    std::vector<int> more_var; 
    void my_func(); 
}; 

Wechseln zu:

template<int myint> 
struct test_static { 
    protected: 
    char some_var; 
    std::vector<int> more_var; 
}; 

template <int myint, bool mybool> 
struct test : private test_static<myint> { 
    void my_func() { 
     // default case 
    } 
}; 
template <int myint> 
struct test<myint,false> : private test_static<myint> { 
    void my_func() { 
     // special case 
    } 
}; 

Natürlich, wenn Sie einen vollständigen Überblick aller Mitglieder nach außen wollen, sie nicht protected in erster Linie machen und verwenden Sie public anstelle von private Vererbung.

3

Zuerst auf this question auf dem SFINAE-Prinzip, um meinen Speicher zu aktualisieren, habe ich versucht, das Ergebnis, das Sie suchen, mit minimaler Redundanz im Code zu erhalten.

Ich habe auch den wikipedia Artikel über das Thema, was mich darauf hingewiesen, dass Sie ähnlich zu boost::enable_if bedingt Ihre Funktion inmplementation wählen eine Funktionalität benötigen:

// simplified version of boost::enable_if_c and disable_if_c to match your exact need 

template <bool B> 
struct enable_if_c { 
    typedef void type; 
}; 

struct enable_if_c<false>{}; 

template <bool B> 
struct disable_if_c { 
    typename void type; 
}; 

struct disable_if_c<true> {}; 

template<bool mybool, typename T> 
struct test { 
    template <bool d> 
    typename enable_if_c<d>::type my_func_impl(){ 
     cout << "true" << endl; 
    } 
    template <bool d> 
    typename disable_if_c<d>::type my_func_impl(){ 
     cout << "false" << endl; 
    } 
    void my_func(){ my_func_impl<mybool>(); } 
}; 

Sie können festlegen, die my_func_impl Stellen außerhalb der Struktur mit der folgende Syntax:

template <bool mybool, typename T> 
template <bool d> 
typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){ 
    cout << "true" << endl; 
} 

der schwierige Punkt des Problems ist, dass Sie nicht auf einer einfachen Überlastung verlassen können, da Sie die s wollen ame Funktion Prototyp, daher die Notwendigkeit, nur die eine oder andere Implementierung zu definieren.

0

Sie können ein wenig Verbesserung der durch diderc, nur durch eine kleine Modifikation bereitgestellt Antwort hinzufügen, die Sie die Verwendung einer Hilfsfunktion zu vermeiden, ermöglicht es, die Ihre Funktionen Namen verschmutzen würden:

Statt:

template <bool d> 
typename enable_if_c<d>::type my_func_impl(){ 
    cout << "true" << endl; 
} 
template <bool d> 
typename disable_if_c<d>::type my_func_impl(){ 
    cout << "false" << endl; 
} 
void my_func(){ my_func_impl<mybool>(); } 

schreiben Sie einfach:

template <bool d = mybool> 
typename enable_if_c<d>::type my_func(){ 
    cout << "true" << endl; 
} 
template <bool d = mybool> 
typename disable_if_c<d>::type my_func(){ 
    cout << "false" << endl; 
} 

Und wenn Sie C++ 11 verwenden können, können Sie enable_if_c und disable_if_c durch std::enable_if ersetzen.

(ich seine Antwort nicht kommentieren kann, so gepostet ich meine eigene)

Verwandte Themen