Verschachtelte templates...



  • Hallo

    folgender Code:

    template<template<class>class>class foo
    {
    public:
    	void blub()
    	{
    	}
    	template<template<class>class>void blub()
    	{
    	}
    };
    
    template<class dub> class bar
    {
    public:
    	void blub()
    	{
    		dub d;
    		d.blub(); //OK
    		d.blub<bar>(); //WTF
    	}
    };
    
    int main()
    {
    	bar< foo<bar> > c;
    	c.blub();
    
    	return 0;
    }
    

    Sieht natürlich auf den ersten Blick etwas kryptisch aus, aber in meinem Zusammenhang macht er durchaus sinn.

    Bei der Zeile, die ich mit WTF makiert habe, sagt mir VC2008 (gcc kann man outputmäßig hier vergessen!):

    1>.\main.cpp(19) : error C3207: 'foo<<unnamed-symbol>>::blub' : invalid template argument for '<unnamed-symbol>', class template expected
    1>        with
    1>        [
    1>            <unnamed-symbol>=bar
    1>        ]
    1>        .\main.cpp(7) : see declaration of 'foo<<unnamed-symbol>>::blub'
    1>        with
    1>        [
    1>            <unnamed-symbol>=bar
    1>        ]
    1>        .\main.cpp(16) : while compiling class template member function 'void bar<dub>::blub(void)'
    1>        with
    1>        [
    1>            dub=foo<bar>
    1>        ]
    1>        .\main.cpp(25) : see reference to class template instantiation 'bar<dub>' being compiled
    1>        with
    1>        [
    1>            dub=foo<bar>
    

    Was ist falsch bzw. wie könnte ich das Problem lösen?

    Danke!


  • Administrator

    Die Fehlermeldung sagt eigentlich schon alles. Du musst dem bar einen Templateparameter übergeben. Man kann keine Klassentemplates (beachte Unterschied zu Templateklasse) als Templateparameter übergeben.

    template<class dub>
    class bar
    {
    public:
        void blub()
        {
            dub d;
            d.blub(); //OK
            d.blub<bar<dub> >(); // wird funktionieren ;)
        }
    };
    

    Grüssli



  • Sicher?

    [cpp]template<**template<class>**class>void blub()
    {
    }[/cpp]

    Zumindest sagt mir der Compiler bei deiner Variante (die nicht in meinem Sinne ist, ich will wirklich eine Klassentemplate übergeben!) folgendes:

    error C3207: 'foo<<unnamed-symbol>>::blub' : invalid template argument for '<unnamed-symbol>', class template expected
    


  • Ich denke, dass das Problem wo anderst liegt.

    bar ist innerhalb von bar kein Klassentemplate, da der Name für die Templateklasse bar<dub> steht.

    Also musst du da ein Klassentemplate angeben.:
    z.B

    template<class>
    class k{};
    
    template<class dub> class bar
    {
    public:
        void blub()
        {
            dub d;
            d.blub(); //OK
            d.blub< k >(); //WTF
        }
    };
    

    oder das globale template benutzen:

    template<class dub> class bar
    {
    public:
        void blub()
        {
            dub d;
            d.blub(); //OK
            d.blub< ::bar >(); //WTF
        }
    };
    


  • drakon schrieb:

    template<class dub> class bar
    {
    public:
        void blub()
        {
            dub d;
            d.blub(); //OK
            d.blub< ::bar >(); //WTF
        }
    };
    

    da fehlt jetzt noch das "template" 😉

    template<class dub> class bar
    {
    public:
        void blub()
        {
            dub d;
            d.blub(); //OK
            d.template blub< ::bar >(); //WTF
        }
    };
    

  • Administrator

    *muss seinen Fehler eingestehen*
    Aber aktuell habe ich solche Augen -> 😮
    Irgendwie habe ich das bisher falsch verstanden mit den Template Template Parameter.
    Tjo, man lernt nie aus 🙂
    *wird nochmals das Kapitel dazu durchlesen müssen*

    Sorry für die Falschinformation.

    Grüssli



  • Vielen lieben Dank für eure Antworten. Auf VS2008 läuft der Spaß nun einwandfrei! Mit gcc auch, solange man zwischen < und :: Whitespaces einfügt ("'<:' is an alternate spelling for '

    evilissimo schrieb:

    between '<' and '::'").

    [quote="evilissimo"]da fehlt jetzt noch das "template" 😉

    Das ist interessant. Dieses Konstrukt habe ich zwar schon einige Male gesehen, aber nie wirklich verstanden, wozu es gut ist (explizite Instatiierung - wozu?!). Kannst du mit zu dem entsprechenden Paragraphen im Standart weiterleiten? Vielen Dank!


  • Administrator

    RudolfRenntier schrieb:

    Das ist interessant. Dieses Konstrukt habe ich zwar schon einige Male gesehen, aber nie wirklich verstanden, wozu es gut ist (explizite Instatiierung - wozu?!). Kannst du mit zu dem entsprechenden Paragraphen im stan**** weiterleiten? Vielen Dank!

    Jetzt kann ich doch noch helfen, hoffentlich 🙂
    Ich kenne zwar den Standard Paragraphen nicht, wo das erklärt wird, da ich den Standard nicht habe, aber die Sache ist recht simpel und geht auf das gleiche zurück, wie das Problem mit typename bei einem Typen, welcher von einem Templateparameter abhängig ist.

    template<typename T>
    void foo(std::vector<T>& values)
    {
      typename std::vector<T>::iterator iter = values.begin();
      // ...
    }
    

    Dieses Problem sollte bekannt sein. Da der Kompiler die Klasse vector noch nicht vollständig kennt, nimmt der Kompiler per Default an, dass iterator kein Typ, sondern eine statische Variable ist. Deshalb muss man das typename hinschreiben.

    Bei einem Funktionsaufruf mit Templateparameter ist das ähnlich.

    template<typename T>
    struct Bar
    {
      template<typename X>
      void func()
      {
        // ...
      }
    };
    
    template<typename T>
    void foo(Bar<T>& bar)
    {
      bar.template func<int>();
    }
    

    Ohne das template würde der Kompiler denken, dass func eine Membervariable sei und das erste '<' ein "kleiner als" ist. Was folglich zu einem Fehler führt.

    Referenz: C++ Templates - The complete guide, 7th Printing April 2006, Seite 44-45

    Grüssli



  • Ohne das template würde der Kompiler denken, dass func eine Membervariable sei und das erste '<' ein "kleiner als" ist. Was folglich zu einem Fehler führt.

    VC++ 08 scheint intelligent genug zu sein, um das richtig zu interpretieren.


  • Administrator

    drakon schrieb:

    Ohne das template würde der Kompiler denken, dass func eine Membervariable sei und das erste '<' ein "kleiner als" ist. Was folglich zu einem Fehler führt.

    VC++ 08 scheint intelligent genug zu sein, um das richtig zu interpretieren.

    Sogar bereits der VC++ 03 und 05. Aber das hat nichts mit Intelligenz zu tun, sondern ist schlicht nicht standardkonform 😉
    Ähnliches gilt auch für typename :

    #include <vector>
    #include <iostream>
    
    template<typename T>
    typename std::vector<T>::iterator					// Hier braucht er es.
    foo(std::vector<T>& vec)
    {
    	std::vector<T>::iterator iter = vec.begin();	// Hier nicht, obwohl es nötig wäre.
    
    	std::cout << *iter << std::endl;
    
    	return iter;
    }
    
    int main() 
    {
    	std::vector<int> vec;
    	vec.push_back(0);
    
    	std::cout << *foo(vec) << std::endl;
    
    	test::wait("...");
    
    	return 0; 
    }
    

    (mit VC++ 05 getestet)

    Der VC++ unterstützt ja auch schon seit längerem die doppelten schliessenden Templateklammern: '>>'.
    Usw.
    Ist vielleicht praktisch, aber, soweit ich weiss, nicht standardkonform 🙂

    Grüssli



  • Servus,

    ich habe mir nicht den gesamten Beitrag durchgelesen und entschuldige mich hiermit, falls ich daneben liege 😉

    Suchst du nach ne Möglichkeit verschachtelte Templates zu erstellen? Im allg. sollte man darauf verzichten, da viele es nicht auf den ersten Blick entschlüsseln können.

    template < template < typename, typename > class Container, typename Type >
    class MeineKlasse
    {
      Container< Type, std::allocator < Type > > baz;
    };
    

    und

    MeineKlasse< std::deque, int > ex;
    

    Achja, diese Templateform unterstützen nicht alle Compiler. Der GCC kann's jedenfalls, aber ob es der hoch intelligente VC es frisst 😕 😃

    Gruß,
    Thomas



  • Siassei schrieb:

    Servus,
    ich habe mir nicht den gesamten Beitrag durchgelesen und entschuldige mich hiermit, falls ich daneben liege 😉

    Warum tust du es dann?
    Und schreibst etwas, was gar nichts mit dem Thema zu tun hat und von der Flameware mal abgesehen. 🙄


Anmelden zum Antworten