Pergunta

Estou implementando um leitor de configuração genérico. A idéia é que eu tenho um aplicativo quais configurações podem ser booleanas, números inteiros e strings. Depois, tenho uma classe de configuração em que os getters para essas configurações são implementados, a classe Config leva um cliente no construtor, para que saiba que ele lerá as configurações para esse cliente.

Estou tendo problemas em ter esse trabalho, acho que estou usando mal o impulso :: função confundindo com ponteiro de função simples.

Nos mapas, eu gostaria de ter referências enquanto o boost::function deve ser binded apenas no tempo de leitura de configuração, pois lá alocou um Config instância para o cliente fornecido.

O problema é que não posso usar ponteiros de função sem typedefs e isso complica o trabalho de modelo, qualquer solução mais sábia?

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

Atualização funcionou usando referências de função em mapas em vez de aumentar :: função

Foi útil?

Solução

Você não pode usar os ponteiros da função de membro como ponteiros de função normal, a menos que as funções do membro sejam static. Você deve usar Boost bind com uma instância de objeto específica:

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

A razão pela qual os ponteiros da função de membro (não estático) não são os mesmos que os ponteiros normais da função (ou ponteiros da função de membro estático) é que as funções de membro têm um argumento "zeroth" oculto, que é o this ponteiro dentro da função do membro.

Além disso, sua declaração do boost::function Objetos devem ser apenas por exemplo

boost::function<bool()>

Que lidará com todos os tipos de funções que retornam um bool e sem argumentos.


Se o seu compilador for novo o suficiente, você também pode querer mudar para usar std::function e std::bind.


Após a sua edição para mostrar com ponteiros de função de membro: você deve chamar os ponteiros de função também corretamente, como

(config.*configIter->second)();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top