Pregunta

Estoy implementando un lector de configuración genérica. La idea es que tengo una aplicación qué configuración puede ser booleano, enteros y cadenas. Luego tengo una clase de configuración donde se implementan los Getters para dicha configuración, la clase de configuración toma a un cliente en el constructor, para que sepa que leerá la configuración para ese mismo cliente.

Tengo problemas para que eso funcione, creo que estoy mal uso de Boost :: Función confundiéndolo con un puntero de función simple.

En los mapas me gustaría tener referencias mientras el boost::function estaré vinculado solo en la hora de lectura de configuración desde allí, he asignado un Config instancia para el cliente dado.

El problema es que no puedo usar punteros de función sin typedefs y esto complica el trabajo de la plantilla, ¿alguna solución más sabia?

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

Actualización funcionó utilizando referencias de funciones en mapas en lugar de aumentar :: función

¿Fue útil?

Solución

No puede usar punteros de la función miembro como punteros de función normal, a menos que las funciones de los miembros estén static. En su lugar deberías usar Boost Bind con una instancia de objeto específica:

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

La razón por la que los punteros de la función miembro (no estatales) no son lo mismo que los punteros de la función normal (o punteros de la función de miembro estático) es que las funciones de los miembros tienen un argumento oculto "cero", es decir, el es el this Puntero dentro de la función miembro.

Además, su declaración de la boost::function Los objetos deben ser solo, por ejemplo

boost::function<bool()>

Que manejarán todo tipo de funciones que devuelven un bool y no tomando argumentos.


Si su compilador es lo suficientemente nuevo, es posible que también desee cambiar para usar std::function y std::bind.


Después de su edición para mostrar con los punteros de la función de los miembros: también debe llamar a los punteros de la función correctamente, como

(config.*configIter->second)();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top