Domanda

Sto implementando un lettore di impostazione generica. L'idea è che ho un'applicazione che le impostazioni possono essere booleane, numeri interi e stringhe. Quindi ho una classe di configurazione in cui vengono implementati i getter per tali impostazioni, la classe di configurazione prende un cliente nel costruttore, in modo che sappia che leggerà le impostazioni proprio per quel cliente.

Ho problemi a farlo funzionare, penso che sto abusando di Boost :: Funzione confondendolo con il semplice puntatore della funzione.

Nelle mappe vorrei avere riferimenti mentre il boost::function deve essere vincolato solo al momento di lettura della configurazione poiché ho assegnato a Config istanza per il cliente dato.

Il problema è che non posso usare puntatori di funzioni senza typedefs e questo complica il lavoro del modello, qualsiasi soluzione più saggia?

#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;
}

AGGIORNAMENTO ha funzionato utilizzando i riferimenti alla funzione in map anziché boost ::

È stato utile?

Soluzione

Non è possibile utilizzare i puntatori della funzione membro come puntatori di funzionalità normali, a meno che le funzioni del membro non siano static. Dovresti invece usare Aumenta il legame Con un'istanza specifica dell'oggetto:

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

Il motivo per cui i puntatori (non statici) della funzione membro non sono uguali ai puntatori della funzione normale (o puntatori di funzioni membri statici) è che le funzioni dei membri hanno un argomento "zeroeth" nascosto, cioè il this puntatore all'interno della funzione membro.

Inoltre, la tua dichiarazione del boost::function Gli oggetti dovrebbero essere solo ad es.

boost::function<bool()>

Che gestirà tutti i tipi di funzioni che restituiscono un bool e non prendere argomenti.


Se il tuo compilatore è abbastanza nuovo, potresti anche voler cambiare std::function e std::bind.


Dopo la tua modifica da mostrare con i puntatori della funzione membro: devi anche chiamare correttamente i puntatori della funzione, come

(config.*configIter->second)();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top