4

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

BenMorel
  • 34,448
  • 50
  • 182
  • 322
codeJack
  • 2,423
  • 5
  • 24
  • 31

1 Answers1

3

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)();
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • yes I have been thinking about this solution as well, but I cannot have a config instance at that stage since I potentially have many customers, this is why I only want to allocate it at config read time and then get rid of it – codeJack Nov 07 '13 at 12:01
  • @codeJack Then you can't really use `boost::function` (or `std::function`), but have to use member function pointers. Will update my answer. – Some programmer dude Nov 07 '13 at 12:04
  • anyway I can achieve that considering I would need to typedef such function pointers and I have a lot of templated functions there, I have been trying that out with no success. I will update the question with that. thanks – codeJack Nov 07 '13 at 12:06