Question

I am trying to understand how to initialize private const std::map properly. I have studied this well-known topic but none of the answers was suitable for me, because I am forced to use old gcc and boost versions (gcc 4.4, boost 1.41 -> C++11 features are limited, boost::asign::map_list_of does not compile) and, moreover, I don't want to use class member function for std::map initialization due to need of doing that outside the class at the time of the object construction.

However, there is overloaded constructor for std::map that accepts two iterators (this thread inspired me too), and this is my workaround:

template <typename Arg, typename Callback>
class CallbackSelector
{
    private:
        const std::map<Arg, Callback> Mapping;

    public:
        CallbackSelector(std::pair<Arg, Callback> _Mapping[]):
            Mapping(_Mapping, _Mapping + sizeof(_Mapping)/sizeof(std::pair<Arg, Callback>))
            {
                //BOOST_ASSERT(sizeof _Mapping)/(sizeof (std::pair<Arg, Callback>)) == 2);
                std::cout << "sizeof _Mapping " << sizeof _Mapping << std::endl;
                std::cout << "sizeof (std::pair<Arg, Callback>) " << sizeof (std::pair<std::string, boost::function<void(void)> >) << std::endl;
            };
};

void PamEvent() {}

void DefaultEvent() {}

int main(int argc, char** argv)
{
    std::pair<std::string, boost::function<void(void)> > _Mapping[] =
    {
        std::make_pair("pam:", boost::bind(&PamEvent)),
        std::make_pair("none", boost::bind(&DefaultEvent))
    };
    std::cout << "sizeof _Mapping " << sizeof _Mapping << std::endl;
    std::cout << "sizeof (std::pair<Arg, Callback>) " << sizeof (std::pair<std::string, boost::function<void(void)> >) << std::endl;

    CallbackSelector<std::string, boost::function<void(void)> > Selector(_Mapping);
}

(The full executable version of this example)

If I uncomment the line with BOOST_ASSERT macro, this code will not be compiled, because the size of Mapping is unequal to 2 due to an error of passing the std::pair<std::string, boost::function<void(void)> > _Mapping[] into the CallbackSelector class constructor. You can verify this by looking at the output:

sizeof _Mapping 80                                 //in the int main()
sizeof (std::pair<Arg, Callback>) 40

sizeof _Mapping 8                                  //in the CallbackSelector constructor
sizeof (std::pair<Arg, Callback>) 40               //the array size has decreased tenfold

I'll be glad if someone could find this (apparently?) simple mistake. Thank you.

Was it helpful?

Solution

There's no way to determine the size of an array given just a pointer to it. You could either pass the size as a separate argument:

CallbackSelector(std::pair<Arg, Callback> mapping[], size_t size) :
    Mapping(mapping, mapping + size)

or infer it as a template parameter:

template <size_t size>
CallbackSelector(std::pair<Arg, Callback> (&mapping)[size]) :
    Mapping(mapping, mapping + size)

or, in C++11 or later, you could take an initializer_list argument

CallbackSelector(std::initializer_list<std::pair<Arg, Callback>> mapping) :
    Mapping(mapping.begin(), mapping.end())

// Usage example
CallbackSelector<std::string, boost::function<void(void)> > selector {
    {arg1, callback1}, 
    {arg2, callback2}
};

(Note: I took the liberty of renaming _Mapping, a reserved name that you shouldn't have been using).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top