Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Failed to compile because of incompatible cv-qualifiers

I have two template method

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 purpose is apply member method of class T on these args

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 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));
like image 656
Phạm Văn Thông Avatar asked Dec 29 '25 05:12

Phạm Văn Thông


1 Answers

std::map::insert is an overloaded function. You cannot take its address unless you explicitly specify the overload you're interested about - how else would the compiler know?

The easiest way to solve your problem is to have apply accept an arbitrary function object and wrap your call to insert in a generic lambda.

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

Usage:

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

live wandbox example

The additional syntactic boilerplate is unfortunately impossible to avoid. This might change in the future, see:

  • N3617 aimed to solve this issue by introducing a "lift" operator.

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

I'm not sure if overloaded member functions are supported in the above proposals though.


You can alternatively use your original solution by explicitly specifying the overload you're intersted in 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 it's not very pretty. It can be probably improved with some better template argument deduction, but not by much.

like image 90
Vittorio Romeo Avatar answered Dec 30 '25 21:12

Vittorio Romeo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!