Probleme mit Funktions Template



  • Hi,

    ich habe ein kleines Problem mit dem Aufrufen einer Template Funktion 🙄

    Ich habe eine Funktion geschrieben mit der ich auf Maps zugreifen kann. Da ich verschiedene Maps (<CString, CString>, <int, list<CString> >) verwende habe ich ein Template daraus gemacht.

    template<class R, class S, class T, class U> R getMapValue(S Parameter, std::map<T, U> &Map) 
    	{ 
    		std::map<T, U>::iterator MapIterator;
    		MapIterator = Map.find(Parameter);
    		return (*MapIterator).second;		
    	}
    

    Zuvor hatte das Template einen genau definierten Rückgabewert (und da hat auch noch alles funktioniert), nämlich CString.

    template<class S, class T, class U> CString getMapValue(S Parameter, std::map<T, U> &Map) 
    	{ 
    		std::map<T, U>::iterator MapIterator;
    		MapIterator = Map.find(Parameter);
    		return (*MapIterator).second;		
    	}
    

    Als ich zu der ganz allg. Form gewechselt bin konnte sich der Compiler an der Stelle dann nicht mehr entscheiden (bzw. zuordnen) was für einen Wert er zurückliefern muss und ich hab ne Fehlermeldung bekommen.

    Hab dann nachgeschaut wie der Templateaufruf aussehen muss ...

    CString Value = getMapValue<CString, CString, CString, CString> ("Filename", CommandLineParameterMap);
    

    (Die Map ist <CString, CString> )

    Ich dachte durch explizite Angabe der Typen schafft der Compiler das, doch jetzt bekomme ich folgende Fehlermeldung:

    "error C2275: 'CString' : illegal use of this type as an expression"

    Kann mir jemand mal auf die Sprünge helfen und sagen wie der Aufruf richtig ist??

    Legolas



  • Hi

    Was soll es den machen ?

    Für welches Programm benötigst du es ?

    Gruß mo



  • sind das nicht ein bisschen viel Parameter? S ist doch immer gleich T, und R ist immer gleich U, oder? Also könnte man die Funktion so schreiben, und der Compiler wär happy:

    template <typename K, typename V>
    V getMapValue(K key, std::map<K, V> const& m) {
      return m.find(key)->second;
    }
    

    Allerdings muss man sich dann fragen, was passiert, wenn der Schlüssel nicht gefunden wird. So wie die Funktion dasteht (auch deine längere Version) bekommst du undefiniertes Verhalten, weil find im Falle des nicht-Findens den end()-Iterator zurückliefert, und der darf nicht dereferenziert werden. Dabei könnte man aber auch bedenken, dass es bereits eine Memberfunktion von map gibt, die fast das tut was du willst: operator[]

    Map[Key] liefert den Wert, der zu Key gehört, zurück. Wenn Key nicht gefunden wird, wird ein default-Konstruierter Wert zu diesem Key (bei CString also wahrscheinlich ein Leerstring) in die Map eingefügt, und dieser dann zurückgegeben.



  • Hab das Template jetzt so geändert und bekomme immer noch einen Compilerfehler

    template <typename K, typename V> V getMapValue(K key, std::map<K, V> const& m) 
    { 
       return m.find(key)->second; 
    }
    
    ...
    
    CString Dummy = getMapValue<CString, CString>("Filename", CommandLineParameterMap);
    

    hier meckert er:

    error C2275: 'CString' : illegal use of this type as an expression

    und wenn ich es so mache:

    Dummy = getMapValue("Filename",CommandLineParameterMap);
    

    dann:

    error C2782: 'V __thiscall Data::getMapValue(K,const class std::map<K,V,struct std::less<K>,class std::allocator<V> > &)' : template parameter 'K' is ambiguous.

    Also wenn ich ihn nicht angebe, dann meckert er dass er ihn nicht zuordnen kann und wenn ich ihn explizit definiere dann 😕

    So ein Mist ...



  • Zeig mal ein wenig mehr Kontext um die Zeile "CString Dummy = getMapValue<CString, CString>("Filename", CommandLineParameterMap)". Ich bin übrigens überrascht, dass getMapValue auf einmal eine Memberfunktion geworden ist. Sag das doch dazu.



  • Okee, ich dachte das Ganze drumherum lass ich mal weg ... aber ihr habt es nicht anders gewollt 😃

    Ich habe eine Klasse "Data" in die ich (in der Header Datei) die einzelnen Template Funktionen (zum schreiben, lesen, ändern, usw. der Maps) gepackt habe.
    Aus einer anderen Klasse ruf ich jetzt die Funktionen auf.

    Also ungefähr so: (ich versuche alles unwichtige wegzulassen)

    class Data  
    {
    public:
    template <typename K, typename V> V getMapValue(K key, std::map<K, V> const& m){ 
       return m.find(key)->second; 
    }
    
    std::map<CString, CString> CommandLineParameterMap;
    };
    
    class XYZ
    {
       void getValues();
       Data* pData;
    }
    
    XYZ::getValues{
       CString Dummy = pData->getMapValue("Filename",pData->CommandLineParameterMap);
    }
    

    Also das war jetzt einfach so hingeschrieben, keine Ahnung ob es 100%ig richtig ist aber ich hoffe ihr könnt daraus erkennen was ich mache ...

    Was meintest Du mit mehr Kontext? Eigentlich gibt es da nicht viel was noch interessant sein könnte (zu dem Problem).



  • Lässt sich

    CString temp;

    übersetzen ?



  • Jepp!

    Ich hab mit dem WIzard ne Konsolenanwendung mit MFC Unterstützung gemacht.

    Und wie ich am Anfang ja schon gesagt habe, wenn ich

    template<class S, class T, class U> CString getMapValue(S Parameter, std::map<T, U> &Map)  
        {  
            std::map<T, U>::iterator MapIterator; 
            MapIterator = Map.find(Parameter); 
            return (*MapIterator).second;         
        }
    

    den Rückgabeparameter fix mache (also CString) dann funktioniert ja auch alles wunderbar. Nur wenn ich den auch noch variabel machen will dann ist schicht ...



  • Hä? Was du mir da als Kontext andrehen willst ist syntaktisch Mumpitz, was soll das?



  • Sorry, wenn ich nicht das geschrieben habe was Du gerne hättest... 🙄
    Ich hätte ja gerne dass mir geholfen wird und von da her schreib ich bestimmt nicht vorsätzlich etwas das nichts bringt!!

    Aber egal, ich hab trotzdem keinen Plan was Du dann gerne hättest?!

    Ich habe versucht zu erklären was ich mache und welcher Teil ist jetzt unzureichend??



  • Bin jetzt schon ein wenig weiter gekommen...

    Wenn ich das Template direkt über die main Funktion schreibe dann funktioniert es. Keine Fehlermeldungen und richtiges Ergebnis ...

    Ich greife auf die Map der Klasse Data zu, in der meine Werte stehen.

    template <typename K, typename V> V getMapValue(K key, std::map<K, V> const& m) { 
    	return m.find(key)->second; 
    }
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    ...
    Dummy = getMapValue<CString, CString>("Filename",pData->CommandLineParameterMap);
    ...
    }
    

    Wenn ich allerdings die Template Funktion in die dafür vorgesehene Data Klasse packe (in den Header) dann bekomme ich bei dem Aufruf:

    Dummy = pData->getMapValue<CString, CString>("Filename",pData->CommandLineParameterMap);
    

    die Fehlermeldung:

    error C2275: 'CString' : illegal use of this type as an expression

    😕 Warum geht es nicht mehr, wenn ich die gleiche Funktion nur in eine Klasse packe??

    Hat jemand ne Idee??



  • Hinter deiner Klasse XYZ fehlt ein Semikolon, die Funktionsdefinition von getValues hat keine Parameterliste ... wenn du jetzt sagst, "ist beim Abschreiben passiert", weißt du was ich meine. Sonst hättest du wirklich andere Probleme als template-Funktionen 🤡



  • Nee, der Fehler lag an einem einfachen cast...habs herausgefunden!!

    Für alle die es interessiert:

    Wenn ich beim Aufruf :

    Dummy = pData->getMapValue<CString, CString>("Filename",pData->CommandLineParameterMap);
    

    nicht noch einen expliziten cast auf CString einfüge:

    [cpp]
    Dummy = pData->getMapValue<CString, CString>(CString("Filename"),pData->CommandLineParameterMap);
    [/cpp]

    dann kann er ja nicht wissen dass ich "Filename" als CString verwenden will 🙄 😃

    Trotzdem Danke

    Legolas


Anmelden zum Antworten