I'm trying to understand how std::bind and std::function work.
I cannot get the following code to compile:
#include <iostream>
#include <string>
#include <functional>
void function(int a, float b, std::string const &s)
{
std::cout << "printing function" << std::endl;
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << s << std::endl;
}
int main(int argc, char *argv[])
{
std::bind(&function, 10, 11.1, "hello")();
std::function<void(int, float, std::string const&)> fun = std::bind(&function, 10, std::placeholders::_1, std::placeholders::_2);
fun(0.2, "world");
return 0;
}
the compiler complains that:
main.cpp: In function 'int main(int, char**)':
main.cpp:16:69: error: conversion from 'std::_Bind_helper<false, void (*)(int, float, const std::__cxx11::basic_string<char>&), int, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<void (*(int, std::_Placeholder<1>, std::_Placeholder<2>))(int, float, const std::__cxx11::basic_string<char>&)>}' to non-scalar type 'std::function<void(int, float, const std::__cxx11::basic_string<char>&)>' requested
std::function<void(int, float, std::string const&)> fun = std::bind(&function, 10, std::placeholders::_1, std::placeholders::_2);
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
please, can someone explain? and how do I fix this error?
You are almost there, just change the type of fun to
std::function<void(float, std::string const&)> fun = std::bind(...);
// ^^ no more int here
fun(0.2, "world");
// ^^^^^^^^^^^^ those types must match the above signature
Note that you change the function signature when fixing the first function argument of type int to the value 10. Hence, it can't be in the type of the std::function instantiation.
Further note that Scott Meyers suggests in Item 34 of Effective Modern C++ to replace the std::bind usage with a lambda, e.g.
auto fun = [](float b, std::string const& s){ function(10, b, s); };
// Identical invocation:
fun(0.2, "world");
Related
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;
}
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.
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";
}
running through the following function using gdb in vscode tells me that the deduced argTypes for a function of the form T (*)(const int &, const int *, int &, int) are int const int * int & and int respectively. Is there any way to force the compiler to deduce const Type & when presented with a const Type & argument? Or is there some other means by which I can extract that type information in a useful way?
#include<typeinfo>
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
const char *a[] = { typeid(argTypes).name()... };
for(auto &av :a)
{
std::cout << av << std::endl;
}
}
edit:
A little more context: this function obviously does little to nothing, but the problem function that spawned it also takes in all the arguments to be run with f in a way that they are not deduced, but converted.
This presents a problem for non-copyable objects to be used as const references.
An example of using testfunc is as follows:
#include "testfunc.h"
std::vector<bool> funcToTest(const int &a, const int *b, int &c, int d)
{
std::vector<bool> out;
out.push_back(&a == b);
out.push_back(&c == b);
out.push_back(&d == b);
return out;
}
int main()
{
// put a breakpoint here, and step in, you would see that 'a'
// describes the situation as described above.
testfunc(funcToTest);
}
The issue here is with typeid, not template deduction. If you use
template<typename... Ts>
struct types;
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
types<argTypes...>{};
}
You get an nice error message like
main.cpp: In instantiation of 'void testfunc(T (*)(argTypes ...)) [with T = std::vector<bool>; argTypes = {const int&, const int*, int&, int}]':
main.cpp:30:24: required from here
main.cpp:12:5: error: invalid use of incomplete type 'struct types<const int&, const int*, int&, int>'
12 | types<argTypes...>{};
| ^~~~~
main.cpp:7:8: note: declaration of 'struct types<const int&, const int*, int&, int>'
7 | struct types;
| ^~~~~
which shows you that the function parameter types are correctly deduced.
With typeid if the type is a reference, then it returns the referred to type. It also drops all cv-qualifactions on the types. That means
int main()
{
std::cout << typeid(int).name() << "\n";
std::cout << typeid(int&).name() << "\n";
std::cout << typeid(const int).name() << "\n";
std::cout << typeid(const int&).name() << "\n";
std::cout << typeid(volatile int).name() << "\n";
std::cout << typeid(volatile int&).name() << "\n";
std::cout << typeid(const volatile int).name() << "\n";
std::cout << typeid(const volatile int&).name() << "\n";
}
prints
i
i
i
i
i
i
i
i
I have the below code where I am trying to print the multiplication table of 10.
I have bound the function multiply with two parameters 5 and 2. I am passing the bound function to create a lambda. And then I am attempting to pass the lambda to the for_each loop to print the Multiplication Table. I intutively kind of know that I may be pushing it a bit too far. But I don't know the exact reason. Can someone explain.
#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <functional>
#include <future>
#include <array>
#include <unistd.h>
using namespace std;
using namespace std::placeholders;
int multiply(int a, int b, int c)
{
return a*b*c;
}
int main()
{
auto f = std::bind(multiply, 5, 2, _1);
std::function<int(int,int,int)> f1 = [f](int a){cout << "Multiplication Table (10) :" << f(a) << endl; };
vector<int> vec = {1,2,3,4,5,6,7,8,9,10};
for_each(vec.begin(), vec.end(), f1);
return 0;
}
The error that I am getting is shown below.
/home/karthik/Workspace/cpppen/learning/main.cpp: In function ‘int main()’:
/home/karthik/Workspace/cpppen/learning/main.cpp:26:107: error: conversion from ‘main()::<lambda(int)>’ to non-scalar type ‘std::function<int(int, int, int)>’ requested
std::function<int(int,int,int)> f1 = [f](int a){cout << "Multiplication Table (10) :" << f(a) << endl;};
^
In file included from /usr/include/c++/7/algorithm:62:0,
from /home/karthik/Workspace/cpppen/learning/main.cpp:6:
/usr/include/c++/7/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Funct = std::function<int(int, int, int)>]’:
/home/karthik/Workspace/cpppen/learning/main.cpp:30:40: required from here
/usr/include/c++/7/bits/stl_algo.h:3884:5: error: no match for call to ‘(std::function<int(int, int, int)>) (int&)’
__f(*__first);
~~~^~~~~~~~~~
In file included from /usr/include/c++/7/functional:58:0,
from /home/karthik/Workspace/cpppen/learning/main.cpp:8:
/usr/include/c++/7/bits/std_function.h:701:5: note: candidate: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int, int}]
function<_Res(_ArgTypes...)>::
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
I am passing a function with two bound and one placeholder parameter.
No you're not. Your lambda looks like this:
[f](int a) {
cout << "Multiplication Table (10) :" << f(a) << endl;
}
That is the callable object that you are passing to std::function. Now, the lambda is callable with only one argument, not three. Notice:
[/*...*/](int a){ /*...*/ }
// ^^^^^
// one parameter
Likewise, f is a callable object with only one parameter. You can't call it with three arguments, because you've bound two parameters to specific values, so, for all intents and purposes, there are no three parameters. Maybe this makes it more clear:
auto add = [](int a, int b) { return a + b; };
auto addTo5 = [&add](int a) { return add(a, 5); };
add(1, 2); // ok, lambda takes two parameters
addTo5(3); // ok, lambda takes one parameter
addTo5(1, 2); // not ok, lambda doesn't take two parameters
std::function<int(int, int)> fadd = add; // ok
std::function<int(int)> faddTo5 = addTo5; // ok
std::function<int(int, int)> faddTo5fail = addTo5; // not ok, same reason
// addTo5 is approximately what std::bind does: It generates an object which has
// several variables "fixed", and so only takes the placeholder arguments that aren't
// specified.
So, the fix is to change f1's type to reflect what you are actually storing; a callable that takes an int and returns nothing:
std::function<void(int)> f1 = /*...*/;
// ^^^^
// lambda returns nothing