unresolved overload with bind and make_pair

905 views Asked by At

I am trying to copy all of the keys of a map into another by using std::for_each and boost::bind.

I am getting compile error saying

 error: no matching function for call to 
 ‘bind(<unresolved overloaded function type>, boost::arg<1>&, boost::arg<1>&)’

Below my code.

 using namespace boost;
 map<string,int32_t> A;

 typedef map<string,string>  BType;
 BType B;

 std::for_each(A.begin(), A.end(), 
         bind(&BType::insert,&B,bind(&std::make_pair,_1,_1)));

Do you know what is wrong?

1

There are 1 answers

2
Dietmar Kühl On BEST ANSWER

The key problem is that you can't take the address of an overload set: std::make_pair is a function template and you don't even state what instantiation(s) you are talking about. Likewise std::map<K, V>::insert is overloaded, e.g., with a version taking one element and a version taking a range.

Even if you could take the address of an overloaded function in some form, you actually don't really want to if you can help it! The reason is that calling through a function pointer or a member function pointer is a lot more expensive than calling an inline function and calls through function pointers are much harder to inline: the compiler has to proof that a particular [member] function pointer always refers to the same [member] function.

The solution to both problems is to give bind() a function object with a templated function call operator which simply delegates to the appropriate function. For example:

struct make_a_pair {
    template <typename T0, typename T1>
    std::pair<T0, T1> operator()(T0&& t0, T1&& t1) {
        return std::make_pair(std::forward<T0>(t0), std::forward<T1>(t1));
    }
};

When using C++03 you'd use T0 const& and T1 const& instead of T0&& and T1&& and you'd just pass the arguments instead of using std::forward<>(). In a C++11 setting you'd probably rather return a type using decltype(). A similar function object for inserting could look like this:

struct inserter {
    template <typename M, typename T>
    void operator()(M* map, T&& value) {
        map->insert(std::forward<T>(value));
    }
};

With these two function objects in place you could use your bind() expressions:

std::for_each(A.begin(), A.end(),
    boost::bind(inserter(), &B, boost::bind(make_a_pair(), _1, _1)));

Right now I can't quite test this easily but something along those lines should work, assuming pairs of _1 and _1 are what is desired. It seems, you really want to create a mapping from the key to the key in which case you'd need to appropriately project the keys of the original map, e.g., using another function object:

struct project1st {
    template <typename T0, typename T1>
    typename std::remove_const<T0>::type
    operator()(std::pair<T0, T1> const& p) const {
        return p.first;
    }
};

This function object removes a const from the first T0 if there is any (if the pair is from a std::map<K, V> the pair will be of type std::pair<K const, V>) before returning the result. You'd replace each _1 with a suitable std::bind() expression using this function object, i.e., with

boost::bind(project1st(), _1)