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.
Related
Check the below code.
#include <future>
template <class F, class... Args>
void do_something(F f, Args... args) {
using return_type = typename std::result_of<F(Args...)>::type;
// Why below gives an error?
std::packaged_task<return_type(Args...)> task(f, args...);
}
int func(int a, int b) {
}
int main() {
do_something(func, 1, 2);
}
The packaged_task constructor gives a following error.
error: no matching function for call to 'std::packaged_task<int(int, int)>::packaged_task(int (*&)(int, int), int&, int&)'
8 | std::packaged_task<return_type(Args...)> task(f, args...);
The thing I don't understand is that why f and args became a reference type in the constructor? The Args... were int, int types whereas args... just became int&, int&. Where is this coming from?
packaged_task do not have the signature you want.
compiler is saying there is no such function. (probably with candidates below it)
If I have a function with variable arguments, with one of them being a callback function, how would the bind function for that work?
Current implementation as below:
template <typename... Args>
bool CallWithArgs(std::function<void (String&, Args... args)> cbk, Args... args)
{ .... }
The above function is being called from a separate class using a future:
bool value = true;
auto f1 = std::bind(&CallWithArgs, rawPtr, _1, _2);
std::future<bool> fut = std::async(f1, cbk, value);
fut.wait();
Is there anyway to represent variable parameters in the placeholders of the std::bind function? Running into compile issues with the present implementation.
note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
bind(_Func&& __f, _BoundArgs&&... __args)
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter ‘_Func’
Since you can't use C++14's generic lambdas you can make your own by making a functor. If you have
struct CallWithArgsFunctor
{
pointer_type pointer_to_call_on;
CallWithArgsFunctor(pointer_type pointer_to_call_on) : pointer_to_call_on(pointer_to_call_on) {}
template<typename... Args>
auto operator()(Args&&... args) -> decltype(CallWithArgs(pointer_to_call_on, std::forward<Args>(args)...))
{
return CallWithArgs(pointer_to_call_on, std::forward<Args>(args)...)
}
};
then you can use it in your code block like
bool value = true;
std::future<bool> fut = std::async(CallWithArgsFunctor{rawPtr}, cbk, value);
fut.wait();
This allows overload resolution to work in the body of the call operator instead of you having to cast the function pointer to the type you want to call.
If you can upgrade to C++14 your code would just become
bool value = true;
auto f1 = [=](auto&&... args){ return CallWithArgs(rawPtr, std::forward<decltype(args)>(args)...); };
std::future<bool> fut = std::async(f1, cbk, value);
fut.wait();
I would like to pass a template method as a template argument.
I don't understand why I am getting this error:
no known conversion for argument 1 from '<unresolved overloaded function type>' to 'void (B::*&&)(int&&, double&&)
Here is the code:
struct A {
template <class Fn, class... Args>
void f(Fn&& g, Args&&... args) {
g(std::forward<Args>(args)...);
}
};
struct B {
template <class... Args>
void doSomething(Args&&... args) {}
void run() {
A a;
a.f(&doSomething<int, double>, 1, 42.); // error here
}
};
int main() {
B b;
b.run();
return 0;
}
Any ideas?
The root cause for the error is that you need an object to call the member function. However, with current code, the error is not that straightforward.
Change calling site to
a.f(&B::doSomething<int, double>, 1, 42.)
And you will see much better error:
error: must use '.' or '->' to call pointer-to-member function in 'g
(...)', e.g. '(... ->* g) (...)'
doSomething is a member function, as such, it cannot be called without an object, which you are trying to do
g(std::forward<Args>(args)...);
^
where is the instance?
One solution to this is to wrap doSomething in a lambda:
a.f([](B& instance, int a, int b) { instance.doSomething(a, b); }, *this, 1, 42.);
If you can use C++17, you could also use std::invoke:
template <class Fn, class... Args>
void f(Fn&& g, Args&&... args) {
std::invoke(g, std::forward<Args>(args)...);
}
and then when calling f:
a.f(&B::doSomething<int, double>, this, 1, 42.);
I think the snippet of code is self explanatory, but basically the template function ExecFunc should be able to execute another function and return its result. I know I can achieve similar results using decltype instead of result_of, but this question is to understand why what I've written does not work: the snippet does not compile on gcc v4.9.2.
This is what I have:
#include <type_traits>
int f(int i)
{
return i;
}
template<class F, class T>
auto ExecFunc(F f, T arg) -> typename std::result_of<F()>::type
{
return f(arg);
}
int main() {
auto a = ExecFunc(f, 3);
return 0;
}
and this is the compiler output:
prova.cpp: In function ‘int main()’:
prova.cpp:15:26: error: no matching function for call to ‘ExecFunc(int (&)(int), int)’
auto a = ExecFunc(f, 3);
^
prova.cpp:15:26: note: candidate is:
prova.cpp:9:6: note: template<class F, class T> typename std::result_of<F()>::type ExecFunc(F, T)
auto ExecFunc(F f, T arg) -> typename std::result_of<F()>::type
^
prova.cpp:9:6: note: template argument deduction/substitution failed:
prova.cpp: In substitution of ‘template<class F, class T> typename std::result_of<F()>::type ExecFunc(F, T) [with F = int (*)(int); T = int]’:
prova.cpp:15:26: required from here
prova.cpp:9:6: error: no type named ‘type’ in ‘class std::result_of<int (*())(int)>’
N.B.
this question might look like a duplicate of this one but the accepted solution doesn't work for me (at least, as far as I can tell I have incorporated the solution in my code).
The function you have is int f(int i) but you are calling F() which is unknown. std::result_of<F()>::type should be std::result_of<F(T)>::type.
Live Example
The problem is with the parameter of result_of, it should be:
-> typename std::result_of<F(T)>::type
This is the perfect time to use decltype
template<class F, class T>
auto ExecFunc(F f, T arg) -> decltype(f(arg))
Why is "TArgs" ambiguous in my Example?
The compiler should know the only existing function signature
virtual CGame::NetCreatePlayer(CNetPeer* _pPeer, int _ObjectID, const CNetMessage& _ObjectData, bool _bAuthority);
and deduce correct TArgs in this function:
template<typename... TArgs >
void INetInterface<TSubClass>::NetCall(void(TSubClass::*_pFunc)(CNetPeer*, TArgs...), CNetPeer* _pPeer, TArgs... _Params);
I want to call it like this:
CNetMessage obj;
//...
NetCall(&CGame_Server::NetCreatePlayer, _pClient, 0, obj, true);
CGame_Server inherits CGame.
Compiler output:
4> error C2782: 'void INetInterface<CGame>::NetCall(void (__thiscall CGame::* )(CNetPeer *,TArgs...),CNetPeer *,TArgs...)'
: template parameter 'TArgs' is ambiguous
4> NetInterface.h(82) : see declaration of INetInterface<CGame>::NetCall'
4> could be 'int, const CNetMessage&, bool'
4> or 'int, CNetMessage, bool'
It can't be 'int, CNetMessage, bool', right?
Is there a way to get around this problem?
I tried casting to const CNetMessage& but strangely enough that does not help.
And no there are no other member functions with that same name.
NetCall(&CGame_Server::NetCreatePlayer, _pClient, 0, obj, true);
There are two places in this call from which TArgs can be deduced:
From the member function pointer's type, the compiler deduces TArgs == int, const CNetMessage&, bool
From the parameters 0, obj, true, the compiler deduces TArgs == int, CNetMessage, bool
The results conflict. To fix this, use the identity trick to put the second TArgs into a non-deduced context:
template<class T> struct identity { using type = T; };
template<class T> using identity_t = typename identity<T>::type;
template<typename... TArgs >
void INetInterface<TSubClass>::NetCall(void(TSubClass::*_pFunc)(CNetPeer*, TArgs...),
CNetPeer* _pPeer, identity_t<TArgs>... params);
As a side note, _Params is a reserved identifier, along with _ObjectData and _ObjectID; you should rename them.