Question

I'm implementing a generic setting reader. The idea is that I have an application which settings can be boolean, integers and strings. Then I have a Config class where the getters for such settings are implemented, the config class takes a customer in the constructor, so that it knows it will read settings for that very customer.

I'm having troubles in having that working, I think I am misusing boost::function confusing it with plain function pointer.

In the maps I'd like to have references while the boost::function shall be binded only at config read time since there I have allocated a Config instance for the given customer.

The problem is that I cannot use function pointers without typedefs and this complicates the template work, any wiser solution ?

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

UPDATE it did work by using function references in maps rather than boost::function

Was it helpful?

Solution

You can't use member function pointers as normal function pointers, unless the member functions are static. You should instead use Boost bind with a specific object instance:

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

The reason that (non-static) member function pointers are not the same as normal function pointers (or static member function pointers) is that member functions have a hidden "zeroeth" argument, that is the this pointer inside the member function.

Also, your declaration of the boost::function objects should be only e.g.

boost::function<bool()>

That will handle all type of functions returning a bool and taking no arguments.


If your compiler is new enough, you might also want to change to be using std::function and std::bind.


After your edit to show with member function pointers: You have to call the function pointers correctly as well, like

(config.*configIter->second)();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top