I have a function object typedef std::function<bool(Event*)> Handler. A member function always gets assigned to this object. So, I am using std::bind to achieve that.
Handler f = std::bind(&LevelSystem::switchLevel, this, std::placeholders::_1);
f(new Event("test"));
This code above works as expected, but I want to wrap the std::bind in a helper function for cleaner code. This is what I have come up with.
template<class Func> inline Handler MemFn(Func &&f) {
return std::bind(f, this, std::placeholders::_1);
}
And the usage will be:
Handler f = MemFn(&LevelSystem::switchLevel);
I am getting an error when using this function:
No viable conversion from
'__bind<bool(LevelSystem::*&)(Event *), System *,std::__1::placeholders::__ph<1> &>' to
'Handler' (aka 'function<bool(Event *)>')
I do not understand the error.
You're trying to create a bind expression that will call a bool (LevelSystem::*)(Event*) function on a System object, which is not possible.
You need to bind the correct dynamic type of this to the function, as your comment indicates you've now done by passing the this pointer to MemFn.
If you're always going to pass a pointer-to-member-function to MemFn then there's no point passing it by rvalue-reference, you might as well just pass the pointer-to-member. Doing that allows you to deduce the class type, so you can then cast this to that type:
template<typename Ret, typename Class, typename Param>
inline Handler MemFn(Ret (Class::*f)(Param)) {
return std::bind(f, static_cast<Class*>(this), std::placeholders::_1);
}
Related
here is function to register.
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
and a specific handler to register:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
now I want to apply the Handler to Register Function, compiler complains
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
while specificly write out the type is OK:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
but the latter has ugly API. How can I get the first on work?
How can I get the first on work?
Add an overload for plain function pointers:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
I see some ways.
(1) If you can modify the RegisterCmdHandler() function and you don't need to know, inside it, what types ReqT and RestT are, I suggest you to avoid at all std::function and accept sync_handler as a simple template type.
I mean
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
This is a very flexible solution because F can be a function, a function pointer, a std::function, a lambda (also a generic lambda, so this solution is more flexible than using std::function), another type of class/struct with an operator(), a value returned from a std::bind. In short: a generic callable.
(2) If you can modify the RegisterCmdHandler() function but you need to know (and use) the ReqT and RestT, you can follows the plain function pointer way (see Maxim Egorushkin's answer for the syntax). Unfortunately this works with function pointers only and doesn't works (by example) when sync_handler is a lambda.
(3) If you can't modify RegisterCmdHandler() but you can use C++17, you can use std::function deduction guides and call the function as follows
RegisterCmdHandler(1, std::function{SomeHandler});
or, maybe better if you have to call it in different places, call it through a converter
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
calling it as follows
CallRegisterCH(1, SomeHandler);
(4) if you can't modify RegisterCmdHandler() and you have to use C++11 or C++14... well... explicating the template types
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
seems to me the better way.
Other ways you can explicit the std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
but seems to me almost the same thing.
I need to get the address of an overloaded template function that involves SFINAE. A good example of this scenario would be boost::asio::spawn found here...
https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/spawn.html
How would I find the address of this particular instance...
template<
typename Function,
typename Executor>
void spawn(
const Executor & ex,
Function && function,
const boost::coroutines::attributes & attributes = boost::coroutines::attributes(),
typename enable_if< is_executor< Executor >::value >::type* = 0);
I've unsuccessfully tried this...
using Exec = boost::asio::io_context;
using Func = std::function<void(boost::asio::yield_context)>;
void (*addr)(Exec, Func) = boost::asio::spawn;
boost::asio::spawn is not a function. It is a function template. It's a blueprint from which functions can be created. There's no way to get a pointer to a function template because it's a purely compile-time construct.
boost::asio::spawn<Func, Exec> is a function overload set, but it has no overload that matches the signature void(Exec,Func). Remember, default function arguments are just syntactic sugar. Those arguments are still part of the function's signature.
Those two issues make getting a pointer to boost::asio::spawn hard and ugly. It would be much easier to use a lambda. A lambda will let you preserve type deduction and take advantage of the default arguments:
auto func = [](auto&& exec, auto&& func) {
boost::asio::spawn(std::froward<decltype(exec)>(exec),
std::forward<decltype(func)>(func));
};
Even if you absolutely need a function pointer, a lambda is still probably the way to go. You lose parameter type deduction, but can still take advantage of the function's default arguments:
void(*addr)(const Exec&, Func) = [](const Exec& exec, Func func) {
boost::asio::spawn(exec, std::move(func));
};
This works because captureless lambdas can be converted to raw function pointers.
If you really, absolutely need a pointer directly to one of the spawn instantiations for some reason, you can get it, but it's not pretty:
using Exec = boost::asio::io_context::executor_type;
using Func = std::function<void(boost::asio::yield_context)>;
void(*addr)(const Exec&, Func&, const boost::coroutines::attributes&, void*) = boost::asio::spawn<Func&, Exec>;
You lose a lot in doing so though. Not only do you lose argument type deduction and the default arguments, you also lose the ability to pass both lvalues and rvalues to the function since you no longer have a deduced context for forwarding references to work in. I've to get a pointer to the instantiation accepting an lvalue-reference to the function. If you want it to accept rvalue-references instead, use
void(*addr)(const Exec&, Func&&, const boost::coroutines::attributes&, void*) = boost::asio::spawn<Func, Exec>;
Also note that this function takes four parameters. Call it with, i.e.
addr(my_io_context.get_executor(), my_function, boost::coroutines::attributes{}, nullptr);
Example
Tried to put this solution as an edit in the question where it'd be visible right off, but the moderators seem to think it's better to force a reader through to here...
using Exec = boost::asio::io_context;
using Func = std::function<void(boost::asio::yield_context)>;
using Attr = boost::coroutines::attributes;
void (*addr)(const Exec&,
Func&&,
const Attr&,
typename enable_if< is_executor< Executor >::value>::type*
) = boost::asio::spawn<Func, Exec>;
Yes, ugly but not too too bad.
As I understand it,
std::bind perfectly forwards both the callable object it wraps and the arguments to that callable object;
the std::bind return object is itself movable and/or copyable, depending on whether the callable object and its arguments are movable and/or copyable;
a std::bind return object may be nested, in which case the outer std::bind return object is movable and/or copyable, just as when binding other callable objects.
Therefore, I would expect the following code snippet to compile okay. Instead, the code generates a spew of compiler errors at the last two statements in main().
#include <functional>
template<typename HandlerType>
void call_handler(HandlerType&& handler)
{
handler();
}
template<typename HandlerType>
void do_something(HandlerType&& handler)
{
auto f = std::bind(
&call_handler<HandlerType&>,
std::forward<HandlerType>(handler));
f();
}
int main()
{
auto a = [&]() {};
do_something(a);
do_something(std::move(a));
auto b = std::bind([&]() {});
do_something(b); // <- compiler error!
do_something(std::move(b)); // <- compiler error!
}
Each of the two problem line spews errors without the other. To eliminate all errors, I must comment out both lines.
Here's a sample error, from g++ 4.9.2 in Cygwin, at the call to f() in do_something():
(4 of 103): error: no match for call to ‘(std::_Bind<void (*(std::_Bind<main()::<lambda()>()>))(std::_Bind<main()::<lambda()>()>&)>) ()’
Here's a sample error from Visual Studio 2013, at the same line:
1>C:\Program Files (x86)\Microsoft Visual Studio12.0\VC\include\functional(1149): error C2664: 'void (HandlerType)' : cannot convert argument 1 from 'void' to 'std::_Bind<false,void,main::<lambda_2b8ed726b4f655ffe5747e5b66152230>,> '
What's going on? Do I misunderstand std::bind?
Specifically, how can I
bind a callable object? and
pass that std::bind return object to a function taking a universal reference? and
nest that std::bind return object in another std::bind?
My goal is for the underlying callable object and its arguments to be perfectly forwarded.
EDIT: To clarify, I want to pass the wrapped callable object and its arguments by value, not by reference, so std::ref won't help—at least, not as a full solution. The reason is that my real code is more complex and involves passing the f std::bind return object across a thread boundary, and both the a and b std::bind return objects may go out of scope in the original thread before call_handler calls f(), so a and b need to copy or move into f, not be mere references. That said, my question is specifically about std::bind and perfect forwarding, and for the purpose of asking a good question, I've distilled out everything not needed to reproduce the specific compiler errors I mentioned.
Your assumption 1 is wrong, bind always passes the bound arguments as lvalues to the callable it is wrapping. To demonstrate this, change the bind expression within do_something to the following
auto f = std::bind(
&call_handler<decltype(handler)>,
std::forward<HandlerType>(handler));
The following line will then fail to compile
do_something(std::move(a));
because decltype(handler) is an rvalue reference, but bind will try to call call_handler with an lvalue reference to the bound lambda expression you passed it in main.
Now for what's going wrong in the second half of your example. bind has special handling for nested bind expressions, which it will recognize and evaluate. However, in your example, you don't want that to happen. Instead, you want the nested bind to be forwarded as is to call_handler, which will then invoke it.
Boost provides boost::protect which lets you mask the real type of the nested bind and thus prevent its evaluation by the outer bind.
Unfortunately, there is no std::protect equivalent, but it's not difficult to write it yourself.
template<typename T>
struct protect_wrapper : T
{
protect_wrapper(const T& t) : T(t)
{}
protect_wrapper(T&& t) : T(std::move(t))
{}
};
template<typename T>
std::enable_if_t<!std::is_bind_expression<std::decay_t<T>>::value,
T&&
>
protect(T&& t)
{
return std::forward<T>(t);
}
template<typename T>
std::enable_if_t<std::is_bind_expression<std::decay_t<T>>::value,
protect_wrapper<std::decay_t<T>>
>
protect(T&& t)
{
return protect_wrapper<std::decay_t<T>>(std::forward<T>(t));
}
Just wrap your inner bind expression with protect, and your code will compile.
auto b = protect(std::bind([&]() {}));
do_something(b);
do_something(std::move(b));
Live demo
I've a code:
class cabc{
public:
void pr()
{
cout<<"abcdef";
}
};
int main()
{
cabc cap;
auto f = async(cap.pr);
f.get();
return 0;
}
This code is not working. I know the same thing can be done using:
auto f = async(&cabc::pr,cap);
This is working. But why the first approach is not working?
cap.pr is an incomplete member function call expression. You must follow it with parentheses containing the appropriate function arguments to make a valid C++ expression.
You can't therefore pass cap.pr to std::async or any other function.
To pass a member function to std::async you need to use the syntax you found:
auto f=std::async(&capc::pr,cap);
Though in this case, you need to be aware that the cap object is copied. You could also use
auto f=std::async(&capc::pr,&cap);
to just pass a pointer to cap.
If the pointer-to-member-function syntax is unwelcome then you can use a lambda:
auto f=std::async([&]{cap.pr();});
This isn't quite the same: it doesn't pass the member function pointer and object pointer to std::async, it passes a lambda object containing a reference to cap that calls its pr member function directly. However, the result is essentially the same.
Have a look at the function signature for async:
template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async( Function&& f, Args&&... args );
(from cppreference)
It should be apparent that, firstly, whatever Function&& is, it can't be the case that cap.pr and &cabc::pr are both of that type.
More precisely, though, Function&& is supposed to be an rvalue-reference to a function pointer. &cabc::pr is just the syntax for a pointer-to-member-function, and because it's a member function, a pointer to the object itself needs to be the first argument. If cap.pr were a C-style function pointer, then your first sample might work.
Honestly, I'm not sure why your second sample works since you're not passing in a pointer to your object.
There are a number of other answers to similar questions. For example: How to, in C++11, use std::async on a member function?
I would like to do something like
template<typename InstanceType>
void add_test(void (InstanceType::* test_method )(void*),
std::tr1::shared_ptr<InstanceType> user_test_case)
{
boost::function<void ()> op;
op = boost::bind<InstanceType>(test_method, *user_test_case);
But it says:
1>d:\boost\boost/bind/mem_fn.hpp(359): error: a pointer to a bound function may only be used to call the function
1> return (t.*f_);
What is wrong here?
The 1st template argument of bind is the return type. So, it should be void. Or just omit it.
boost::function signature doesn't match the one of the bound function. Make it function<void(void *)>.
The functor you create should accept 1 argument, so provide the appropriate argument placeholder.
Finally, you can bind to the shared_ptr, directly.
The bottom line: boost::function<void (void *)> op = boost::bind(test_method, user_test_case, _1);