std::bind() throwing error when this is not passed - c++

I am trying to understand std::bind(). I am trying to understand the code in the post https://riptutorial.com/cplusplus/example/7541/std--function-used-with-std--bind.
Code is as below.
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:
std::function<void(int, const std::string&)> m_CbFunc = nullptr;
void foo()
{
if (m_CbFunc)
{
m_CbFunc(100, "event fired");
}
}
};
class B
{
public:
B(int x) : y(x)
{
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);
anObjA.m_CbFunc = aFunc;
}
void eventHandler(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
void DoSomethingOnA()
{
anObjA.foo();
}
int y;
A anObjA;
};
int main(int argc, char *argv[])
{
B anObjB(4);
anObjB.DoSomethingOnA();
}
I couldn't understand why we are using this in bind call
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2)
eventHandler is taking 2 parameters and we are binding with placeholders. Not sure why do we need to pass this. If I remove this, I am getting below error.
/usr/include/c++/6/functional:1286:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
main.cpp: In constructor ‘B::B(int)’:
main.cpp:34:27: error: no match for ‘operator=’ (operand types are ‘std::function&)>’ and ‘std::_Bind&)>(std::_Placeholder<1>, std::_Placeholder<2>)>’)
anObjA.m_CbFunc = aFunc;
^~~~~
In file included from main.cpp:10:0:
/usr/include/c++/6/functional:1929:7: note: candidate: std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {int, const std::basic_string, std::allocator >&}]
operator=(const function& __x)
^~~~~~~~

The this is needed because eventHandler() is not a static method. std::bind() is used specifically when you want to use non-static methods of your class.
Note that personally, I find it ugly and don't like using it. I use lambdas instead.
anObjA.m_CbFunc = [=](int i, const std::string&s) { eventHandler(i,s); };
Even though the syntax for lambdas is kind of ugly, I don't think it's as ugly or obscure as bind. But that's just my preference.

Related

std::function and std::bind: how to load a std::bind with a function template

I use a function template to load a std::bind obj, my code:
#include <iostream>
#include <functional>
template<typename RT_, typename ...Args>
void installCallback(const char name[], const std::function<RT_(Args...)> &func)
{
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
installCallback<int, int, int>("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));// didn't work either
// this work well
std::function<int(int, int)> fun = std::bind(add, std::placeholders::_1, std::placeholders::_2);
installCallback("add02", fun);
return 0;
}
, I got this error:
/home/tong/Documents/awesome_auto_drive/awe_auto/sample/module/main.cpp:20:90: error: no matching function for call to ‘installCallback(const char [6], std::_Bind_helper<false, int (&)(int, int), const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type)’
20 | installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
| ^
$./main.cpp:6:6: note: candidate: ‘template<class RT_, class ... Args> void installCallback(const char*, std::function<_Res(_ArgTypes ...)>&&)’
6 | void installCallback(const char name[], std::function<RT_(Args...)> &&func)
| ^~~~~~~~~~~~~~~
$./main.cpp:6:6: note: template argument deduction/substitution failed:
$./main.cpp:20:90: note: ‘std::_Bind_helper<false, int (&)(int, int), const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type’ {aka ‘std::_Bind<int (*(std::_Placeholder<1>, std::_Placeholder<2>))(int, int)>’} is not derived from ‘std::function<_Res(_ArgTypes ...)>’
20 | installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
| ^
sample/module/CMakeFiles/module.dir/build.make:62: recipe for target 'sample/module/CMakeFiles/module.dir/main.cpp.o' failed
make[2]: *** [sample/module/CMakeFiles/module.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:2665: recipe for target 'sample/module/CMakeFiles/module.dir/all' failed
make[1]: *** [sample/module/CMakeFiles/module.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2
who can tell me, what happened?
You are running into template function argument deduction rules. std::bind does not return a std::function, and your passed int for Args... is only a prefix to Args.... So C++ attempts to deduce the rest of Args... and fails with that error.
A quick fix is
template<class Sig>
void installCallback(const char name[], const std::function<Sig> &func)
then
installCallback<int(int, int)>
this leaves the body of installCallback bereft of Args....
Now,
installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
cannot work, because bind (a) is not a std function, and (b) doesn't know what its argument types are.
It is also pointless here.
installCallback("add01", add);
is logically equivalent and less filled with noise. It still won't compile; however in c++17 this will:
installCallback("add01", std::function(add));
due to deduction guides. The bind version will not.
As a general rule, if you are using std bind, instead use a lambda. In c++11 lambdas can replace 95% of bind usage mechanically, and in c++14 it becomes 99.9%, with the remaining 0.1% being features of bind you probably shouldn't be using and don't know exists (and usually won't until it breaks your code in surprising ways; passing std bind to std bind).
I like the answer from #yakk-adam-nevraumont. I think it is very clear and explains things aptly; the superior answer so far so I upvoted it. The only other contribution I can make is that I was able to arrive at a similar conclusion (deduction rules not yielding std::function) using the boost library to de-mangle the printed type names of each expression. See code below modified from the sample #JoeT provided and working snippet here.
You'll notice the deduced type of fun1 is different than the explicit type of fun2.
#include <functional>
#include <iostream>
#include <typeinfo>
#include <boost/core/demangle.hpp>
template<typename RT_, typename ...Args>
void installCallback(const char name[], const std::function<RT_(Args...)> &func)
{
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
auto fun1 = std::bind(add, std::placeholders::_1, std::placeholders::_2);
std::function<int(int, int)> fun2 = std::bind(add, std::placeholders::_1, std::placeholders::_2);
char const* name = typeid( fun1 ).name();
// Outputs: std::_Bind<int (*(std::_Placeholder<1>, std::_Placeholder<2>))(int, int)>
std::cout << boost::core::demangle(typeid(fun1).name()) << std::endl;
// Outputs: std::function<int (int, int)>
std::cout << boost::core::demangle(typeid(fun2).name()) << std::endl;
return 0;
}

std::function as a (non) const input parameter sent by &

I wonder why std::function<...(...)> & needs to be specified as const when passed as an input parameter to a function. AFAIK there is no way to change it, right? Here is an example that compiles and runs fine. If I remove the const qualifier I get an error:
#include <iostream>
#include <functional>
//int foo(std::function<int(int)> &f)
int foo(const std::function<int(int)> &f)
{
return f(6);
}
int main(int argc, char **argv)
{
auto f1 = [=](int i){ if (i<5) {return 8*2;} else {return 2;} };
auto f2 = [=](int i){ if (i>3) {return i*i;} else {return 2;} };
std::cout << foo(f1) << "\n";
}
When I use the declaration without the const I get the following error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:13:21: error: cannot bind non-const lvalue reference of type ‘std::function<int(int)>&’ to an rvalue of type ‘std::function<int(int)>’
std::cout << foo(f1) << "\n";
^
In file included from /usr/include/c++/7/functional:58:0,
from main.cpp:2:
/usr/include/c++/7/bits/std_function.h:685:7: note: after user-defined conversion: std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = main(int, char**)::<lambda(int)>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = int; _ArgTypes = {int}]
function<_Res(_ArgTypes...)>::
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:4:5: note: initializing argument 1 of ‘int foo(std::function<int(int)>&)’
int foo(std::function<int(int)> &f)
^~~
A lambda is not a std::function, but a std::function can be created from a lambda. When you pass either f1 or f2 to foo(), the compiler must construct a temporary std::function object to give to the f parameter. However, an lvalue reference to a non-const object cannot be bound to a temporary object, exactly as the error message says.
To allow the passing of a temporary object, the f parameter must be changed to take the std::function by either:
value
lvalue reference to a const object
rvalue reference
Otherwise, you have to construct the std::function yourself in a variable, then pass that instead:
#include <iostream>
#include <functional>
//int foo(const std::function<int(int)> &f)
int foo(std::function<int(int)> &f)
{
return f(6);
}
int main(int argc, char **argv)
{
auto f1 = [=](int i){ if (i<5) {return 8*2;} else {return 2;} };
auto f2 = [=](int i){ if (i>3) {return i*i;} else {return 2;} };
std::function<int(int)> f = f1;
std::cout << foo(f) << "\n";
}

std::function pointer error: cannot convert &A::a to type std::function<>&&

I'm trying to map string to function pointer, so that I can call the function with iter->second(arg) instead of if-else.
I have written a simple one without class, and it works as expected.
But when I modify it as below, it shows compile errors.
#include <functional>
#include <iostream>
#include <unordered_map>
#include <string>
using std::string;
class A{
private:
int a(int num, string s) { return s.size() + num; }
int b(int num, string s) { return num - s.size(); }
public:
void ido(string str){
typedef std::function<int(int, string)> process_func;
std::unordered_map<string, process_func> m;
m.insert(std::make_pair<string, process_func>("a", &A::a));
// using std::placeholders::_1;
// m.insert(std::make_pair<string, process_func>("a", std::bind(&A::a, this, _1)));
// m["a"] = std::bind(&A::a, this, _1);
// m.insert({{"a", &A::a}, {"b", &A::b}});
auto x = m.find(str);
if(x == m.end()) {
std::cout << "Not supported!" << std::endl;
}
std::cout << x->second(10, "hello") << std::endl;
}
};
int main(int argc, char* argv[]) {
A a;
a.ido(string(argv[1]));
return 0;
}
The errors are:
function.cc: In member function ‘void A::ido(std::string)’:
function.cc:17:65: error: no matching function for call to ‘make_pair(const char [2], int (A::*)(int, std::string))’
m.insert(std::make_pair<string, process_func>("a", &A::a));
^
function.cc:17:65: note: candidate is:
In file included from /usr/include/c++/4.8.2/utility:70:0,
from /usr/include/c++/4.8.2/tuple:38,
from /usr/include/c++/4.8.2/functional:55,
from function.cc:1:
/usr/include/c++/4.8.2/bits/stl_pair.h:276:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
make_pair(_T1&& __x, _T2&& __y)
^
/usr/include/c++/4.8.2/bits/stl_pair.h:276:5: note: template argument deduction/substitution failed:
function.cc:17:65: note: cannot convert ‘&A::a’ (type ‘int (A::*)(int, std::string) {aka int (A::*)(int, std::basic_string<char>)}’) to type ‘std::function<int(int, std::basic_string<char>)>&&’
m.insert(std::make_pair<string, process_func>("a", &A::a));
What does the error mean? How to fix it?
While your functions 'a' and 'b' do not depend on 'this' (they do not access anything inside class A), the compiler is not smart enough to deduce this. So the error means that you are trying to convert 'pointer to method' to 'pointer to function', which is incorrect conversion. 'Pointer to method' requires and object to be called on. You need to declare methods 'a' and 'b' as 'static' to indicate that they are actually standalone functions, not methods of the class.

std::async with shared pointer templated member functions

I'm working on implementing multi-threading in a project, but am running into a wall when it comes to some more complicated uses of std::async. I want to call a member function on a templated object and pass in an argument as a parameter, but I can't get it to work when the template holds a shared pointer.
It's pretty simple to use std::async on member functions, and even templated member functions. I've seen plenty of answers around stack overflow for this specific usage. I've even run some test cases myself:
#include <thread>
#include <future>
#include <iostream>
class Bar
{
public:
Bar () {}
double data;
};
template <typename T>
class Foo
{
public:
Foo () {}
T set_data (T d) { data = d; return data; }
private:
T data;
};
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Works fine
*/
Foo<int> foo1;
auto fut1 = std::async(std::launch::async, &Foo<int>::set_data, &foo1, 42);
fut1.wait();
std::cout << fut1.get() << std::endl;
return 0;
}
This example compiles perfectly fine in gcc 7.4.0 and returns 42 as expected.
My problem comes in when I use shared_ptr in the template. Using the same Foo and Bar classes from above:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>;
auto br = std::make_shared<Bar>;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
I get this error when compiling g++ -pthread test.cpp -o test
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:94: error: no matching function for call to ‘async(std::launch, std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)())’
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
^
In file included from ./foo.h:2:0,
from test.cpp:1:
/usr/include/c++/7/future:1712:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1712:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>); _Args = {Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1712:5: error: no type named ‘type’ in ‘class std::result_of<std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*(Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)()))(std::shared_ptr<Bar>)>’
/usr/include/c++/7/future:1745:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1745:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1745:5: error: no type named ‘type’ in ‘class std::result_of<std::launch(std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)())>’
I thought this maybe was because the reference & wasn't working in the proper order with all those angle brackets for the templates, so I tried using some parentheses:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
fut2.wait();
std::cout << fut2.get().data << std::endl;
return 0;
}
Which results in a shorter error which I also don't understand.
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:75: error: invalid use of non-static member function ‘T Foo<T>::set_data(T) [with T = std::shared_ptr<Bar>]’
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
I am confused why the shared pointers all of a sudden make a difference, and I'm guessing it has to do with type deduction? Any help is appreciated.
EDIT
Thanks to those that responded, here is the solution. The parentheses are not required, and some shared_ptrs were missing.
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
auto bar = std::make_shared<Bar>(2.5);
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar;
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
There are some issues, I think that using a lambda might help you clarify what is going on:
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto op = [foo2, bar]() mutable {return foo2.set_data(std::make_shared<Bar>(bar));};
auto fut2 = std::async(std::launch::async, op);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
You have to pass to the set_data a shared_ptr to Foo. Secondly, the set_data is not const-qualified, so you need a mutable lambda.
Lastly, the future, when returning though get(), will give you a shared_ptr to Bar so you need the operator -> .
You can make the code more efficient moving Foo2 and Bar inside the lambda, but I am trying to keep the answer simple, in particular because I do not know if you want, in your use case to re-use Foo2 and Bar, but you can consider moving inside the lambda.
Regarding your specific code, the following is compiling in g++ 9.1 with C++14, see https://godbolt.org/z/DFZLtb
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, std::make_shared<Bar>());
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
You need to provide a shared_ptr<Bar>as argument and not a Bar and you need to remove the parenthesis around Foo<std::shared_ptr<Bar>>::set_data.
You just have some typos in your code, in first shared_ptr example you pass shared_ptr<Foo> instead of raw ptr Foo* to your function. In the second example first argument Foo* is correct, but second one is Bar instead of shared_ptr<Bar>. Here you have the working example:
class Bar
{
public:
Bar () {}
double data;
};
template <typename T>
class Foo
{
public:
Foo () {}
T set_data (T d) { data = d; return data; }
private:
T data;
};
#include <future>
TEST(xxx, yyy) {
Foo<std::shared_ptr<Bar> > foo;
auto bar = std::make_shared<Bar>();
bar->data = 42;
auto futureResult = std::async(std::launch::async,
&Foo<std::shared_ptr<Bar> >::set_data, &foo, bar);
std::cout << futureResult.get()->data << std::endl;
}
As a side note, if you need to run async operation on some data inside your Foo class, better provide the interface that executes this async operation inside your class and returns the future.
std::future<T> runAsyncOper(const T& data);
Your first example with the shared pointer doesn't pass a shared pointer to std::async as a last parameter, it passes a pointer to function (you didn't add the parentheses)
int main()
{
/**
* Works :)
*/
Foo<std::shared_ptr<Bar>> foo2;
auto br = std::make_shared<Bar>();
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, br);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
Problem is that you passed wrong types of arguments to std::async and used incorrectly std::make_shared.
Minimal modification to your code:
auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>();
auto bar = std::make_shared<Bar>();
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, foo2, bar);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
https://wandbox.org/permlink/3YXG56ahFKrZs8GB

Boost phoenix member function operator fails to compile if function has overload

I want to use Boost phoenix member function operator for the class function that has overloads, like here.
The following example fails:
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/operator.hpp>
using namespace std;
using namespace boost::phoenix::placeholders;
struct A
{
int m_id = 1;
int func() const { return 1; }
void func(int id) { m_id = id; }
};
int main()
{
A *a = new A;
auto retVal = (arg1->*&A::func)()(a);
return 0;
}
With error:
In function 'int main()': 17:21: error: no match for 'operator->*'
(operand types are 'const type {aka const
boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::
tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0l>
>}' and '<unresolved overloaded function type>') 17:21: note: candidate is: In
file included from /usr/include/boost/phoenix/operator/arithmetic.hpp:13:0,
from /usr/include/boost/phoenix/operator.hpp:13, from /usr/include/boost
/phoenix/phoenix.hpp:13, from 1: /usr/include/boost/proto/operators.hpp:295:9:
note: template<class Left, class Right> const typename
boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,
boost::proto::detail::not_a_grammar,
boost::mpl::or_<boost::proto::is_extension<Arg>,
boost::proto::is_extension<Right> >, boost::proto::tagns_::tag::mem_ptr, const
Left&, const Right&>::type boost::proto::exprns_::operator->*(Left&&,
Right&&) BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain) ^
/usr/include/boost/proto/operators.hpp:295:9: note: template argument
deduction/substitution failed: 17:28: note: couldn't deduce template parameter
'Right'
However, if I comment the line void func(int id) { m_id = id; } out, it works as expected.
How can I tell which of the overloads to use?
Handling (member) function pointers to overload sets is always a pain. You need to cast the address to a pointer that has the exact signature of the desired overload. In your case, for selection int A::func():
auto retVal = (arg1->*static_cast<int (A::*)() const>(&A::func))()(a);
or a bit more readable, but basically the same:
const auto memFctPtr = static_cast<int (A::*)() const>(&A::func);
auto retVal = (arg1->*memFctPtr)()(a);