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));
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With