How to use bind correctly here? - c++

I can not figure out the correct syntax to bind member functions.
If I have a function that takes a function with a single argument,
how do I pass an object to it?
In the following example, what would be the correct syntax of passing the function?
#include <iostream>
#include <functional>
void caller(std::function<void(int)> f)
{
f(42);
}
class foo
{
public:
void f(int x)
{
std::cout<<x<<std::endl;
}
};
int main()
{
foo obj;
caller(std::bind(&foo::f,obj));
//^Wrong
}
Error was:
a.cpp: In function ‘int main()’:
a.cpp:18:34: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (foo::*)(int); _BoundArgs = {foo&}; 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<std::_Mem_fn<void (foo::*)(int)>(foo)>]((* & obj))’ from ‘std::_Bind_helper<false, void (foo::*)(int), foo&>::type {aka std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo)>}’ to ‘std::function<void(int)>’
caller(std::bind(&foo::f,obj));

Placeholders create a "space" for the actual arguments to be bound later:
int main()
{
foo obj;
caller(std::bind(&foo::f, &obj, std::placeholders::_1));
// ^ placeholder
// ^ address or even foo()
}
These placeholders are needed to correctly generate an appropriate signature for the std::bind result to be bound to the std::function<void(int)>.
You may also want to use the address of your object, or std::ref (so it won't be copied); this will vary on what you want the semantics to be.

There is an implicit first argument to member functions, which is the this point. You need to send it as a pointer; you also need a placeholder for the int argument. So:
caller(std::bind(&foo::f, &obj, std::placeholders::_1));
// ^ ^^^^^^^^^^^^^^^^^^^^^^^

You need to specify that the created function object takes a parameter using a placeholder:
std::bind(&foo::f,obj, std::placeholders::_1)

Related

Why am I getting "error: no match for ‘operator->*’" when the parameters on both sides look correct?

I'm trying to call a function from within a template function inside a template.
The call itself, however, doesn't compile, instead I get the following error:
/home/alexis/tmp/b.cpp: In instantiation of ‘bool callback_manager<C>::call_member(F, ARGS ...) [with F = bool (main()::foo::*)(int, int, int); ARGS = {int, int, int}; C = std::vector<std::shared_ptr<main()::foo> >]’:
/home/alexis/tmp/b.cpp:43:47: required from here
/home/alexis/tmp/b.cpp:15:19: error: no match for ‘operator->*’ (operand types are ‘std::shared_ptr<main()::foo>’ and ‘bool (main()::foo::*)(int, int, int)’)
if(!(c->*func)(&args...))
~~^~~~~~~~
Here is a simplified version of the code I'm trying to compile:
#include <memory>
#include <vector>
template<typename C>
class callback_manager
{
public:
template<typename F, typename ... ARGS>
bool call_member(F func, ARGS ... args)
{
C callbacks(f_callbacks);
for(auto c : callbacks)
{
if(!(c->*func)(args...))
{
return false;
}
}
return true;
}
private:
C f_callbacks;
};
int main()
{
class foo
{
public:
typedef std::shared_ptr<foo> pointer_t;
typedef std::vector<pointer_t> vector_t;
bool the_callback(int, int, int)
{
return true;
}
};
callback_manager<foo::vector_t> m;
m.call_member(&foo::the_callback, 5, 13, 7);
return 1;
}
Looking at the parameters, it seems to be that both are correct:
std::shared_ptr<main()::foo>
and
bool (main()::foo::*)(int, int, int)
The fact is that the ->* operator doesn't work with the std::shared_ptr<>.
The solution is to retrieve the bare pointer like so:
if(!(c.get()->*func)(args...)) ...
It then compiles as expected.
You can also rewrite it as follow, which I think is more cryptic:
if(!(*c).*func)(args...)) ...
(i.e. the shared_ptr::operator * () function returns the pointed to object held by the shared pointer, hence the .* operator is used in this case.)
Replace
if(!(c->*func)(args...))
with
if(!(std::cref(func)(c, args...)))
to use the INVOKE machinery of C++. Or use std::invoke directly.
INVOKE concept in the standard, and std::invoke, where designed to work with pmfs and smart pointers.
Meanwhile, ->* isn't overloaded by smart pointers. So direct use like that won't work.
As a side benefit, now a non member function can be passed in as the func.

How can I bind a member function to a std::function?

I want to do an array of OIS::Keys (int) and of std::function.
I have this :
struct UserCommands
{
OIS::KeyCode key;
std::function<bool(Worms *, const Ogre::FrameEvent& evt)> func;
};
UserInput input;
UserCommands usrCommands[] =
{
{
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
},
};
But when I try to compile this I have this compile error :
In file included from includes/WormsApp.hh:5:0,
/src/main.cpp:2:
/includes/InputListener.hh:26:25: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = UserInput*; _BoundArgs = {bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>](&UserInput::selectBazooka)’ from ‘std::_Bind_helper<false, UserInput*, bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)>::type {aka std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>}’ to ‘std::function<bool(Worms*, const Ogre::FrameEvent&)>’
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
^
What have I done wrong ?
Using a lambda, would be like this (instead of std::bind())
[&](Worms*x, const Ogre::FrameEvent&y) { return input.selectBazooka(x,y); }
The first argument of std::bind is a callable object. In your case, that should be &UserInput::selectBazooka. The object to be associated with a call to that member function (&input) goes afterwards (you reversed this order). Still, you have to use placeholders for the missing parameters:
std::bind(&UserInput::selectBazooka, &input, std::placeholders::_1, std::placeholders::_2)

std::bind and rvalue reference

Let's consider the following piece of code:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget&& ref){ return; }, std::move(w));
return 0;
}
and it triggers error
no match for call to ‘(std::_Bind<main()::<lambda(Widget&&)>(Widget)>) ()’
lambda();
And my question is: Why the error has appeared? After all, I do an explicit cast to rvalue reference – I mean std::move(w) and I take argument by rvalue reference – I mean Widget&& ref.
What's up?
Moreover the the below code works, what makes me worried the more:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget& ref){ return; }, std::move(w));
return 0;
}
It might become clearer if you write down what std::bind schematically does.
// C++14, you'll have to write a lot of boilerplate code for C++11
template <typename FuncT, typename ArgT>
auto
bind(FuncT&& func, ArgT&& arg)
{
return
[
f = std::forward<FuncT>(func),
a = std::forward<ArgT>(arg)
]() mutable { return f(a); }; // NB: a is an lvalue here
}
Since you can call the function object std::bind gives you multiple times, it cannot “use up” the captured argument so it will be passed as an lvalue reference. The fact that you pass bind itself an rvalue only means that there is no copy made on the line where a is initialized.
If you try to compile your example with the schematic bind shown above, you'll also get a more helpful error message from your compiler.
main.cxx: In instantiation of ‘bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’:
main.cxx:10:33: required from ‘struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>’
main.cxx:11:31: required from ‘auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’
main.cxx:18:59: required from here
main.cxx:11:26: error: no match for call to ‘(main()::<lambda(Widget&&)>) (Widget&)’
]() mutable { return f(a); }; // NB: a is an lvalue here
^
main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion>
main.cxx:11:26: note: conversion of argument 2 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match>
auto lambda = bind([](Widget&&){ return; }, std::move(w));
^
main.cxx:18:33: note: conversion of argument 1 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
]() mutable { return f(a); }; // NB: a is an lvalue here
To make it work you need to write it like this:
#include <functional>
#include <iostream>
class Widget{};
int main()
{
Widget a;
auto lf = [](Widget&& par){ };
auto f = std::bind
(
lf,
std::bind
(
std::move<Widget&>, a
)
);
f();
return 0;
}
My compiler is gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

C++1y no viable conversion from std::bind to std::function

I am trying to store a forward function into std::function. If I use std::bind, I get error message like no viable conversion from .... If I use lambda, it compile okay.
Here is sample code
#include <functional>
template<typename Handler>void func1(int a, Handler&& handler) {}
template<typename Handler>void func2(Handler&& handler)
{
// this line compile fine
std::function<void ()> funcA = [handler = std::move(handler)]() { func1(1, std::move(handler)); };
// this line got compile error
std::function<void ()> funcB = std::bind(func1<Handler>, 1, std::move(handler));
}
int main()
{
func2(&main); // this just a sample, I am using functor as argument in real code
}
Trying both g++ --std=c++1y (v4.9.0) and clang++ --std=c++1y (v3.4.1) yield the same result
edit: clang++ error message
main.cpp:8:28: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int
(*&&)()), int, int (*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to
'std::function<void ()>'
std::function<void ()> funcB = std::bind(&func1<Handler>, 1, std::move(handler));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:5: note: in instantiation of function template specialization 'func2<int (*)()>' requested here
func2(&main);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2181:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2192:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'const std::function<void ()> &'
for 1st argument
function(const function& __x);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2201:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'std::function<void ()> &&' for
1st argument
function(function&& __x) : _Function_base()
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2226:2: note: candidate template ignored:
substitution failure [with _Functor = std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>]: no matching function for call to object of
type 'std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>'
function(_Functor);
^
1 error generated.
INTRODUCTION
std::bind will try to call func1<Handler> with an lvalue-reference, but your instantiation of func1 will make it only accept rvalues.
EXPLANATION
Here we have reduced your testcase to the bare minimum to show what is going on, the snippet below is ill-formed and an explanation will follow to why that is.
#include <functional>
template<class T>
void foobar (T&& val);
int main() {
std::function<void()> f = std::bind (&foobar<int>, std::move (123));
}
In the above we will instantiate foobar with T = int, which makes the type of argument val to be an rvalue-reference to int (int&&).
std::move(123) will move-construct our value to be stored inside the object created by std::bind, but the Standard says that when std::bind later invokes the stored function, all arguments are passed as TiD cv &; ie. as lvalues.
This behavior is mandated by the Standard (n3797), as stated in section [func.bind.bind]p10.
By changing the previous ill-formed snippet into the following, no error will be raised, since foobar<int> now accepts an lvalue-reference; suitable to be bound to the lvalue passed to our function by the function-object returned by std::bind.
std::function<void()> f = std::bind (&foobar<int&>, std::move (123));
???
#include <functional>
#include <type_traits>
#include <iostream>
int main() {
auto is_lvalue = [](auto&& x) {
return std::is_lvalue_reference<decltype(x)> { };
};
auto check = std::bind (is_lvalue, std::move (123));
bool res = check (); // res = true
}
in short: function has to be copyable. bind with rvalue returns non-copyable object. Workaround is to capture/bind with shared_ptr containing abovementioned value

template argument deduction/substitution failed, when using std::function and std::bind

I have a compile error when using std::function in a templated member function, the following code is a simple example:
#include <functional>
#include <memory>
using std::function;
using std::bind;
using std::shared_ptr;
class Test {
public:
template <typename T>
void setCallback(function<void (T, int)> cb);
};
template <typename T>
void Test::setCallback(function<void (T, int)> cb)
{
// do nothing
}
class TestA {
public:
void testa(int a, int b) { }
};
int main()
{
TestA testA;
Test test;
test.setCallback(bind(&TestA::testa, &testA, std::placeholders::_1, std::placeholders::_2));
return 0;
}
And come with the following compile error:
testtemplate.cpp: In function ‘int main()’:
testtemplate.cpp:29:92: error: no matching function for call to
‘Test::setCallback(std::_Bind_helper)(int, int),
TestA, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type)’
testtemplate.cpp:29:92: note: candidate is: testtemplate.cpp:10:7:
note: template void Test::setCallback(std::function)
testtemplate.cpp:10:7: note: template argument
deduction/substitution failed:
testtemplate.cpp:29:92: note: ‘std::_Bind(TestA*, std::_Placeholder<1>,
std::_Placeholder<2>)>’ is not derived from ‘std::function’
I'm using C++11 and g++ 4.7
To figure out the problem let separate statements:
auto f = bind(&TestA::testa, &testA, _1, _2); // OK
test.setCallback(f); // <<--- Error is here
setCallback needs to know type of T and it can't deduce it from f, so give it a type
test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
You can make type deduction work with some variant of:
template<typename CALLBACK>
void setCallback(CALLBACK cb) {
typedef CALLBACK::first_argument_type T;
static_assert(is_same_type<CALLBACK,function<void(T,int)>>::value);
...
}
This way CALLBACK can be determined by looking at the argument. It might get into trouble if bind doesn't actually return a std::function but rather something that can be cast as one. I'm not sure.