Frage

Ich implementiere einen generischen Einstellungsleser. Die Idee ist, dass ich eine Anwendung habe, die Einstellungen booleschen, Ganzzahlen und Zeichenfolgen sein können. Dann habe ich eine Konfigurationsklasse, in der die Getters für solche Einstellungen implementiert werden. Die Konfigurationsklasse nimmt einen Kunden in den Konstruktor, so dass sie weiß, dass sie Einstellungen für diesen Kunden liest.

Ich habe Probleme, das zu arbeiten, ich denke, ich missbrauche Boost :: Funktion, das es mit einfachem Funktionszeiger verwirrt.

In den Karten würde ich gerne Referenzen haben, während die boost::function soll nur zur Konfigurationsleszeit gebunden werden, da ich dort a zugewiesen habe Config Instanz für den gegebenen Kunden.

Das Problem ist, dass ich keine Funktionszeiger ohne Typedefs verwenden kann, und dies kompliziert die Vorlagenarbeit, eine klügere Lösung?

#include "Config.h"

class ConfigReader
{

    ConfigReader();

    template<class R>
    R readConfig(std::string customer, std::string settingName);

private:

        typedef bool (Config::* BoolConfigFunctor) () const;
    std::map<std::string, BoolConfigFunctor> boolConfigMap;

        typedef int(Config::* IntConfigFunctor) () const;
    std::map<std::string, IntConfigFunctor> integerConfigMap;

        typedef std::string (Config::* StrConfigFunctor) () const;
    std::map<std::string, StrConfigFunctor> stringConfigMap;

    template<class R>
    std::map<std::string, R (Config::* ) () >  getConfigMap();
}

ConfigReader()
{
    // INIT all settings you want to be readable in the functor maps
    boolConfigMap["USE_NEW_VERSION"]    = &Config::useNewVersion;
    boolConfigMap["MAINTENANCE_MODE"]   = &Config::isMaintenance;
    integerConfigMap["TIMEOUT"]         = &Config::getTimeout;
    stringConfigMap["USERNAME"]         = &Config::getUserName;
            ...
}

template<class R>
R readConfig(std::string customer, std::string settingName)
{
    R returnValue;

    typedef typename std::map<AMD_STD::string,  R (Config::* ) () > ConfigMap_t;
    typedef typename ConfigMap_t::const_iterator ConfigMapIter_t;

    ConfigMap_t configMap = getConfigMap<R>();
    ConfigMapIter_t configIter = configMap.find(settingName);

    if (configIter != configMap.end())
    {
        Config config(customer); // Real instance of Config against which we want to call the function

        boost::function<R ()> configFunction;
        configFunction =
                boost::bind(
                        configIter->second,
                        config);

        returnValue= configFunction();
    }

    return returnValue;
}

template<>
std::map<std::string, bool (Config::* ) ()>  ConfigReader::getConfigMap()
{
    return boolConfigMap;
}

template<>
std::map<std::string, int (Config::* ) ()>  ConfigReader::getConfigMap()
{
    return integerConfigMap;
}

template<>
std::map<std::string, string (Config::* ) ()>  ConfigReader::getConfigMap()
{
    return stringConfigMap;
}

Aktualisieren Sie es hat funktioniert, indem Funktionsreferenzen in Karten verwendet werden, anstatt auf Boost :: Funktion

War es hilfreich?

Lösung

Sie können keine Mitgliedsfunktionszeiger als normale Funktionszeiger verwenden, es sei denn, die Mitgliedsfunktionen sind static. Sie sollten stattdessen verwenden Boost Bind mit einer bestimmten Objektinstanz:

boolConfigMap["USE_NEW_VERSION"] = boost::bind(&Config::useNewVersion, someInstanceOfConfig);

Der Grund, warum (nicht statische) Mitgliedsfunktionszeiger nicht mit normalen Funktionen (oder statischen Mitgliedsfunktionszeigern) sind, ist, dass Mitgliederfunktionen ein verstecktes "Zeroeth" -Argument haben, das ist das this Zeiger in der Mitgliedsfunktion.

Auch Ihre Erklärung der boost::function Objekte sollten nur zB sein

boost::function<bool()>

Das wird alle Arten von Funktionen behandeln, die a zurückgeben bool und keine Argumente nehmen.


Wenn Ihr Compiler neu genug ist, möchten Sie möglicherweise auch ändern, um zu verwenden std::function und std::bind.


Nach Ihrer Bearbeitung, um mit Mitgliedsfunktionszeiger zu zeigen: Sie müssen auch die Funktionszeiger korrekt aufrufen, wie

(config.*configIter->second)();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top