Failed to compile due to incompatible cv qualifiers

I have two template methods

template <typename T, typename Ret, typename ...Args>
Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) {
    return (object->*method)(std::forward(args)...);
};

template <typename T, typename Ret, typename ...Args>
Ret apply(T* object, Ret(T::*method)(Args...) const, Args&& ...args) {
    return (object->*method)(std::forward(args)...);
};

      

My goal is to apply a member method of class T for these arguments

this is my test code:

int main() {
    using map_type = std::map<std::string, int>;
    map_type map;
    map.insert(std::make_pair("a", 1));
    std::cout << "Map size: " << apply(&map, &map_type::size) << std::endl; //this code work
    apply(&map, &map_type::insert, std::make_pair("a", 1)); //failed to compile

    return 0;
}

      

This is the compiler error message:

    test.cpp: In function ‘int main()’:
test.cpp:61:58: error: no matching function for call to ‘apply(map_type*, <unresolved overloaded function type>, std::pair<const char*, int>)’
     apply(&map, &map_type::insert, std::make_pair("a", 1));
                                                          ^
test.cpp:11:5: note: candidate: template<class T, class Ret, class ... Args> Ret apply(T*, Ret (T::*)(Args ...), Args&& ...)
 Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) {
     ^~~~~
test.cpp:11:5: note:   template argument deduction/substitution failed:
test.cpp:61:58: note:   couldn't deduce template parameter ‘Ret’
     apply(&map, &map_type::insert, std::make_pair("a", 1));

      

+3


source to share


1 answer


std::map::insert

is an overloaded function. You cannot use your address unless you explicitly specify the overload you are interested in - how else could the compiler know?

The easiest way to solve your problem is to have apply

to accept an arbitrary function object and wrap your call insert

in a generic lambda.

template <typename F, typename ...Args>
decltype(auto) apply(F f, Args&& ...args) {
    return f(std::forward<Args>(args)...);
};

      

Using:

::apply([&](auto&&... xs) -> decltype(auto)
{ 
    return map.insert(std::forward<decltype(xs)>(xs)...);
}, std::make_pair("a", 1));

      

live wandbox example

The extra syntax pattern is unfortunately impossible to avoid. This may change in the future, see:



  • N3617 , which addresses this problem by introducing the "lift" operator.

  • P0119 A. Sutton addresses the problem in a different way by allowing overload sets to basically generate a lambda wrapper for you when passed as arguments.

I'm not sure if the above suggestions support overloaded member functions.


Alternatively, you can use your original solution by explicitly specifying the overload you interact with on the caller side:

::apply<map_type, std::pair<typename map_type::iterator, bool>,
        std::pair<const char* const, int>>(
    &map, &map_type::insert<std::pair<const char* const, int>>,
    std::make_pair("a", 1));

      

As you can see, this is not very pretty. It can probably be improved with some better template argument deduction, but not much.

+6


source







All Articles