Ersatz fuer static object in einem cpp File



  • Halli hallo,

    ich wollte mir eine Enum helper Klasse schreiben mit der ich von enume_type -> string, vice versa und die vorhandenen values als string zurueck bekommen kann schreiben.

    Dabei ist folgendes entstanden:

    template<typename T>
    struct enumHelper
    {
    public:
    	typedef std::map<typename T ,std::string> enumToStr_t;
    	typedef std::function<void (T,const std::string&)> add_callback;
    	typedef std::vector<std::string> nameVec;
    
    	static std::string toString(T algorithm) {
    		return map().at( algorithm );
    	}
    	static T fromString(const std::string& algorithm) {
    		auto static_map = map();
    		for( auto iter = std::begin( static_map  ); iter != std::end( static_map ); iter++) {
    			if(iter->second == algorithm)
    				return iter->first;
    		}
    		assert(0);		
    	}
    
    	static nameVec values() {
    		nameVec ret;		
    		auto static_map = map();	
    
    		std::for_each( std::begin(static_map), std::end(static_map), 
    			[&ret] (enumToStr_t::value_type iter) {
    				ret.push_back( iter.second); 
    		});
    
    		return ret;
    	}
    
    	enumHelper(std::function<void ( typename add_callback ) > initFunc) { 
    		enumToStr_t& m = map();
    
    		initFunc( [&m] ( T v,const std::string& str) {
    			m[v] = str;
    		}); 
    	}
    private:
    	static enumToStr_t& map() { 
    		static enumToStr_t nameMap;
    		return nameMap;
    	};
    };
    

    Um meine static map mit values zu fuellen, erstell ich in einem cpp File zB. sowas:

    hash.h

    enum algo_t { sha_256, sha_512, whirlpool };
            typedef enumHelper<algo_t> algo_enum;
    

    hash.cpp

    static void nameMap(enumHelper<algo_t>::add_callback cb) {
    
    	cb(sha_256, "SHA_256");
    	cb(sha_512, "SHA_512");
    	//cb(sha3_512, "SHA3_512");
    	cb(whirlpool, "WHIRLPOOL");
    
    }
    static algo_enum g_hashAlgorithmEnumHelper( &nameMap );
    

    Jetzt hab ich aber das Problem, dass ich eine statische lib erstelle und (laut stackoverflow) da das "g_hash.." in meinem normalen Programm nicht referenziert wird auch nicht mit ins Programm kommt. Und somit ist meine map leer :(.

    Jetzt ist die Frage, wie ich das static object ersetzen kann aber nicht extra eine init Funktion fuer alles enums aufrufen muss fuer die ich das bereitstellen will?

    Gruessle



  • typedef std::map<typename T ,std::string> enumToStr_t;
    

    Ich verstehe natürlich den Trick, aber ist das nicht ill-formed? Oder hat mein GCC 4.8 noch nicht genug C++11-Unterstützung?


  • Mod

    Sone schrieb:

    typedef std::map<typename T ,std::string> enumToStr_t;
    

    ist das nicht ill-formed?

    ist es, ebenso wie Zeile 33.
    typename ist zwar an einigen Stellen erlaubt, an denen es nicht erforderlich wäre. Trotzdem erlaubt die Grammatik

    typename-specifier:
    typename nested-name-specifier identifier
    typename nested-name-specifier template opt simple-template-id

    weiterhin nicht einen einfachen Bezeichner an dieser Stelle.



  • Sone schrieb:

    typedef std::map<typename T ,std::string> enumToStr_t;
    

    Ich verstehe natürlich den Trick, aber ist das nicht ill-formed? Oder hat mein GCC 4.8 noch nicht genug C++11-Unterstützung?

    Hmm ja weiss jetzt auch ned so genau warum ich da gleich nochmal ein "typename" hingeschrieben hab. Dummerweise sagt mir da mein MSVC2010 nix dazu das, dass nicht erlaubt waere. Aber kennt man ja das der den Standard nicht immer so genau nimmt.

    Aber jetz nochmal zu meinem Problem:

    Und zwar hab ich das jetzt so geloest:

    template<typename T, void(*initFunction)(std::map<T, std::string>& ) >
    struct enumHelper
    {
    //....
    private:
    	static enumToStr_t& map() { 
    		static enumToStr_t nameMap;
    
    		if( nameMap.empty() ) {
    			initFunction( nameMap );
    		}
    
    		return nameMap;
    	};
    

    Und dann in hash

    //hash.h
    	enum algo_t { sha_256, sha_512, whirlpool };	
    
    	namespace detail {
    		void initHashEnum(std::map<algo_t, std::string>& map);
    	}
    	typedef enumHelper<algo_t, &detail::initHashEnum> algo_enum;
    
    //hash.cpp
    namespace detail {
    	void initHashEnum(std::map<algo_t, std::string>& map) {
    
    		map[sha_256] = "SHA_256";
    		map[sha_512] = "SHA_512";	
    		map[whirlpool] = "WHIRLPOOL";
    
    	}
    }
    

    Und sowmit kann ich jetzt ueber:

    std::cout << algo_enum::toString( sha_256) << "\n";
    // bzw
    std::string algo;
    std::cin >> algo;
    algo_t hashType = algo_enum::fromString( algo );
    

    meine Enums fuer die GUI besser aufbereiten.

    Aber jetzt ist die Frage macht das Sinn und ist es einigermassen elegant oder hatte ihr schon mal das gleiche Problem und hab das um einiges besser geloest?

    Gruessle


  • Mod

    Gibt es einen vernünftigen Grund, nicht einfach ein array (sortiert aus pair<enum,const char*> oder einfach aus const char*, falls die Aufzählungskonstanten klein sind) zu verwenden? Die ganze Komplexität dynamischer Initialisierung wird vermieden, der Code wird erheblich kürzer und wahrscheinlich ist es auch noch schneller.



  • camper schrieb:

    Gibt es einen vernünftigen Grund, nicht einfach ein array (sortiert aus pair<enum,const char*> oder einfach aus const char*, falls die Aufzählungskonstanten klein sind) zu verwenden? Die ganze Komplexität dynamischer Initialisierung wird vermieden, der Code wird erheblich kürzer und wahrscheinlich ist es auch noch schneller.

    Muss ehrlich sagen ich steh grad aufn Schlauch. Soll ich dann statt der map ein const char* array nehmen oder statt meiner enumHelper class.



  • Sorry, mein Bruder war zu Besuch.

    Mach niemals enum-helpers!
    Oder wechsle nach Java/C#.

    In C++ reicht nötigenfalls zur lesbaren reinen Ausgabe für den ISO-Prüfer ein Array von C-Strings.

    Siehe YAGNI



  • volkard schrieb:

    Sorry, mein Bruder war zu Besuch.

    Mach niemals enum-helpers!
    Oder wechsle nach Java/C#.

    In C++ reicht nötigenfalls zur lesbaren reinen Ausgabe für den ISO-Prüfer ein Array von C-Strings.

    Siehe YAGNI

    Hmm naja mir gehts drum das ich den User einstellen lassen will was er zB. fuer einen Hash Algorithmus fuer HMAC verwenden will.

    Es gibt jetz wie oben zu sehen ist zB. diese 3 Algorithmen: sha_256, sha_512, whirlpool.
    Wie lassen ich jetzt dann am besten den User waehlen bzw lese die Settings aus einem config file (in json gehalten) wieder raus?

    Da brauch ich doch sowas wie toString(enumType) und fromString(enumType) oder seh ich das falsch?



  • Ne, es reicht wenn du in der Eingabe die Strings prüfst.
    Du brauchst doch nicht beide Richtungen, oder? Also wieder ausgeben?



  • stuxn schrieb:

    Da brauch ich doch sowas wie toString(enumType) und fromString(enumType) oder seh ich das falsch?

    Ja!!!!!!!!!
    Und warum machste das nicht? Warum willst Du das in einen Typ verkleiden? Warum willste neue Begriffe dafür erfinden, neue Klassen?

    Ich wierderhole:

    stuxn schrieb:

    Da brauch ich doch sowas wie toString(enumType) und fromString(enumType) oder seh ich das falsch?

    Naja, fromstring(string), aber wir wußten, was gemeint war. Für komlpexere Lösungen verweise ich Dich an Sone. Der geht zur Zeit ab wie Schmidts Kätzchen und kann Dir alles sehr komlpexidiomatisch darstellen.



  • Sone schrieb:

    Ne, es reicht wenn du in der Eingabe die Strings prüfst.
    Du brauchst doch nicht beide Richtungen, oder? Also wieder ausgeben?

    Ja doch eigentlich schon, da ich ja von meinen Settings Objekt in dem zB steht ich soll fuer HMAC sha_256 verwenden, in das config File ( ist im json Format) schreiben muss.

    volkard schrieb:

    stuxn schrieb:

    Da brauch ich doch sowas wie toString(enumType) und fromString(enumType) oder seh ich das falsch?

    Ja!!!!!!!!!
    Und warum machste das nicht? Warum willst Du das in einen Typ verkleiden? Warum willste neue Begriffe dafür erfinden, neue Klassen?

    Ich wierderhole:

    stuxn schrieb:

    Da brauch ich doch sowas wie toString(enumType) und fromString(enumType) oder seh ich das falsch?

    Naja, fromstring(string), aber wir wußten, was gemeint war. Für komlpexere Lösungen verweise ich Dich an Sone. Der geht zur Zeit ab wie Schmidts Kätzchen und kann Dir alles sehr komlpexidiomatisch darstellen.

    Sollte das dann ca so ausschauen?

    //hash.h
    namespace hash {
       enum algo_t { sha_256, sha_512, whirlpool };  
       const char* toString(algo_t algo);
       algo_t fromString(const std::string& algo);
    }
    
    //hash.cpp
    namespace hash {
    
       static std::pair<algo_t, const char*> hashNamePair[] = { std::make_pair(sha_256, "sha_256"),std::make_pair(sha_512, "sha_512"),std::make_pair(whirlpool, "whirlpool") };
    
       const char* toString(algo_t algo) {
    
          auto r = std::find_if( std::begin( hashNamePair ), std::end( hashNamePair), [algo] (std::pair<algo_t, const char*>& value) { return value.first == algo; });
          return r->second;
       }
    
       algo_t fromString(const std::string& algo) {
    
          auto r = std::find_if( std::begin( hashNamePair ), std::end( hashNamePair), [algo] (std::pair<algo_t, const char*>& value) { return value.second == algo; });
          return r->first;
       }
    
    }
    

    Und das dann fuer jedes enum das ich dem User bereitstellen will?



  • stuxn schrieb:

    Sollte das dann ca so ausschauen?

    Jo, normalerweise schon. Ist recht schlicht, jeder Mitarbeiter vesteht es und es ist falls mehr Performace gebraucht wird, jederzeit unter Beibehalteng der Schnittstelle ausbaubar. Was will man mehr?

    Konkretere Namen, ja.



  • volkard schrieb:

    stuxn schrieb:

    Sollte das dann ca so ausschauen?

    Jo, normalerweise schon. Ist recht schlicht, jeder Mitarbeiter vesteht es und es ist falls mehr Performace gebraucht wird, jederzeit unter Beibehalteng der Schnittstelle ausbaubar. Was will man mehr?

    Konkretere Namen, ja.

    Hmm ja ok versteh ich schon ein bissle. Aber ich hab hier ca 5 Enums. Jetzt schreib ich fuer alle die 2 Funktionen. Nach einer weile faellt mir auf das es zu langsam ist wie du gesagt hast. Jetzt muss ich alle 10 Funktionen aendern. Genau sowas wollte ich halt mit meiner enumHelper class vermeiden.



  • stuxn schrieb:

    Hmm ja ok versteh ich schon ein bissle. Aber ich hab hier ca 5 Enums.

    Oh, 5. Mistige Arbeitgeber.

    stuxn schrieb:

    Jetzt schreib ich fuer alle die 2 Funktionen.

    Null Problemo. Insbesondere dürfen sie ja sogar, wenn sie im Prinzip das selbe tun, eine andere Funkjtion aufrufen zum Beispiel.

    stuxn schrieb:

    Nach einer weile faellt mir auf das es zu langsam ist wie du gesagt hast. Jetzt muss ich alle 10 Funktionen aendern. Genau sowas wollte ich halt mit meiner enumHelper class vermeiden.

    Das sehe ich nicht so. Und das siehst Du auch nicht, nachdem Du es hier ausgesprochen hast. Oder?


Anmelden zum Antworten