Partielle Template-Spezialisierung



  • Hallo zusammen, ich hab ein Problem mit partieller Template-Spezialisierung, und zwar will ich einen Konstruktor haben, der entweder einen Parameter an eine Parent-Klasse weitergibt od. halt void ist.

    Folgendes Beispiel funktioniert:

    template<typename _param>
    class PTest
    {
    public:
    	PTest(_param);
    };
    
    template<>
    PTest<void>::PTest(void)
    {
    	std::cout << "void param" << std::endl;
    }
    
    template<typename _T>
    PTest<_T>::PTest(_T p)
    {
    	std::cout << typeid(_T).name() << " param " << p << std::endl;
    }
    
    void mtest()
    {
    	PTest<void>	vPtest;
    	PTest<int>	iPtest(3);
    
    }
    

    In dem Beispiel ist der Konstruktor des Template PTest für void vollständig definiert (totale Spezialisierung).

    Was ich erreichen will ist folgendes:

    template<class _Base, typename _P>
    class AnotherTest : public _Base
    {
    public:
    	typedef _Base Parent;
    	AnotherTest(_P);
    };
    
    template<class _B>
    AnotherTest<_B, void>::AnotherTest(void):
    	Parent()
    {
    	std::cout << "base class: " << typeid(_B).name() << std::endl;
    	std::cout << "param: void" << std::endl;
    }
    
    template<class _B, typename _X>
    AnotherTest<_B, _X>::AnotherTest(_X x):
    	Parent(x)
    {
    	std::cout << "base class: " << typeid(_B).name() << std::endl;
    	std::cout << "param: " << typeid(_X).name() << x << std::endl;
    }
    
    class Foo
    {
    public:
    	Foo(){}
    };
    
    class Bar
    {
    	int i;
    public:
    	Bar(int _i):i(_i){}
    };
    
    void atest()
    {
    	AnotherTest<Foo, void>	vATest;
    	AnotherTest<Bar, int>	vBTest(4);
    }
    

    Das Template AnotherTest<> ist partiell für den Parameter void spezialisiert.
    Leider kompiliert dieser Code-Teil nicht, daher meine Fragen:
    - Warum?
    - Welche Alternativen habe ich?


  • Administrator

    Kurisu schrieb:

    Leider kompiliert dieser Code-Teil nicht, ...

    Das ist keine Fehlerbeschreibung!

    Aber wenn ich raten müsste, würde ich wohl sagen, liegt es an deinem Konstruktor. Diese Templatespezialisierung nur des Konstruktors funktioniert wahrscheinlich nicht, weil es nicht die gleiche Funktionssignatur ist. Du müsstest für sowas die ganze Klasse spezialisieren:

    template<typename T>
    class Test
    {
    public:
      Test(T const& t); // <- Normal
    };
    
    template<>
    class Test<void>
    {
    public:
      Test(); // <- Spezialisierung
    };
    

    Templates sind schliesslich nicht nur eine dumme Textersetzung. Bei deiner Spezialisierung erwartet der Kompiler dann immer noch einen Parameter, einfach vom Typ void , was natürlich nicht geht. Das gibt aber wahrscheinlich noch keinen Fehler, aber er meckert dann rum, dass es keinen Standardkonstruktor gibt.

    Grüssli



  • Hier der Compiler-Fehler, sorry, vergessen.

    c:\dokumente und einstellungen\chris\eigene dateien\visual studio 2005\projects\template_testing\template_testing\template_testing.cpp(77) : error C2244: 'AnotherTest<_Base,_P>::AnotherTest': Keine Übereinstimmung für Funktionsdefinition mit vorhandener Deklaration gefunden
    c:\dokumente und einstellungen\chris\eigene dateien\visual studio 2005\projects\template_testing\template_testing\template_testing.cpp(68): Siehe Deklaration von 'AnotherTest<_Base,_P>::AnotherTest'
    Definition
    'AnotherTest<_B,void>::AnotherTest(void)'
    Vorhandene Deklarationen
    'AnotherTest<_Base,_P>::AnotherTest(_P)'

    Mit vollständiger Spezialisierung funktioniert das ganze, nur halt mit der partiellen nicht.

    Vollständige Spezialisierung folgt:

    template<class _Base, typename _P>
    class AnotherTest : public _Base
    {
    public:
    	typedef _Base Parent;
    	AnotherTest(_P);
    };
    
    /*
    template<class _B>
    AnotherTest<_B, void>::AnotherTest(void):
    	Parent()
    {
    	std::cout << "base class: " << typeid(_B).name() << std::endl;
    	std::cout << "param: void" << std::endl;
    }*/
    
    template<class _B, typename _X>
    AnotherTest<_B, _X>::AnotherTest(_X x):
    	Parent(x)
    {
    	std::cout << "base class: " << typeid(_B).name() << std::endl;
    	std::cout << "param: " << typeid(_X).name() << x << std::endl;
    }
    
    class Foo
    {
    public:
    	Foo(){}
    };
    
    template<>
    AnotherTest<Foo, void>::AnotherTest(void):
    	Parent()
    {
    	std::cout << "base class: " << typeid(Foo).name() << std::endl;
    	std::cout << "param: void" << std::endl;
    }
    
    class Bar
    {
    	int i;
    public:
    	Bar(int _i):i(_i){}
    };
    
    void atest()
    {
    	AnotherTest<Foo, void>	vATest;
    	AnotherTest<Bar, int>	vBTest(4);
    }
    


  • Kurisu schrieb:

    Hier der Compiler-Fehler, sorry, vergessen.

    c:\dokumente und einstellungen\chris\eigene dateien\visual studio 2005\projects\template_testing\template_testing\template_testing.cpp(77) : error C2244: 'AnotherTest<_Base,_P>::AnotherTest': Keine Übereinstimmung für Funktionsdefinition mit vorhandener Deklaration gefunden
    c:\dokumente und einstellungen\chris\eigene dateien\visual studio 2005\projects\template_testing\template_testing\template_testing.cpp(68): Siehe Deklaration von 'AnotherTest<_Base,_P>::AnotherTest'
    Definition
    'AnotherTest<_B,void>::AnotherTest(void)'
    Vorhandene Deklarationen
    'AnotherTest<_Base,_P>::AnotherTest(_P)'

    Mit vollständiger Spezialisierung funktioniert das ganze, nur halt mit der partiellen nicht.

    Das ist es ja.. Das geht einfach nicht. 😉

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-128361.html



  • Ich hab nicht wirklich Plan, will aber meinen Senf dazugeben. Lautet die Antwort Element-Spezialisierung?


Log in to reply