Storing the result of a bind with placeholders in a std::function - c++

I have been reading up on, how to perform a std::bind on a regular function.
And store the free function or member function into a std::function.
However, if I try to use a placeholder for one argument and an actual value for the other argument; I am not able to make a call(causes compilation error) to the std::function
So I tried the following code:
#include <random>
#include <iostream>
#include <memory>
#include <functional>
int g(int n1, int n2)
{
return n1+n2;
}
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
std::function<int(int,int)> f3 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f3(1) << '\n';
//this works just fine
auto f4 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f4(1) << '\n';
}
I get the following error g++ 4.7
prog.cpp: In function 'int main()':
prog.cpp:17:22: error: no match for call to '(std::function<int(int, int)>) (int)'
std::cout << f3(1) << '\n';
^
In file included from /usr/include/c++/4.9/memory:79:0,
from prog.cpp:3:
/usr/include/c++/4.9/functional:2142:11: note: candidate is:
class function<_Res(_ArgTypes...)>
^
/usr/include/c++/4.9/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}]
function<_Res(_ArgTypes...)>::
^
/usr/include/c++/4.9/functional:2434:5: note: candidate expects 2 arguments, 1 provided

If you're binding an argument to the function int g(int, int), what remains as a callable is a function taking one int as an argument, not two.
Try this:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);

the type of your std::function should be:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);
~~~
one argument
Your bind creates a function with one parameter. That's why you call f3 as this:
std::cout << f3(1) << '\n';
note: candidate expects 2 arguments, 1 provided
should have been your clue

Related

Implicit conversion of initializer lists and perfect forwarding

I'm trying to make perfect forwarding work with initializer lists. For the sake of the example, I'd like to have a variadic function that calls into another function, and still enjoy automatic conversion of initializer lists of the latter:
#include <iostream>
#include <vector>
void hello(std::string const& text, std::vector<int> const& test)
{
std::cout << "hello " << text << " " << test.size() << std::endl;
}
template<class ... Args>
void f(Args&& ... args)
{
return hello(std::forward<Args>(args)...);
}
int main()
{
hello("world", {1,2,3}); // WORKS
f("world", std::vector<int>({1,2,3})); // WORKS
f("world", {1,2,3}); // COMPILER ERROR
}
The error is
example.cpp: In function ‘int main()’:
example.cpp:21:21: error: too many arguments to function ‘void f(Args&& ...) [with Args = {}]’
21 | f("world", {1,2,3});
| ^
example.cpp:12:6: note: declared here
12 | void f(Args&& ... args)
| ^
example.cpp: In instantiation of ‘void f(Args&& ...) [with Args = {}]’:
example.cpp:21:21: required from here
example.cpp:14:15: error: too few arguments to function ‘void hello(const string&, const std::vector<int>&)’
14 | return hello(std::forward<Args>(args)...);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:6:6: note: declared here
6 | void hello(std::string const& text, std::vector<int> const& test)
| ^~~~~
Am I making any obvious mistake here?
The compiler is not able to recognize the type you are sending in the third case.
If you use
f("world", std::initializer_list<int>{1,2,3});
everything works.
This post has some detailed explanation and quotes the relevant part of the standard. It is for a slightly different case but the explanation still applies.
The problem is that the {1, 2, 3} argument to your second call to the templated f function is not sufficiently 'specific' for the compiler to unambiguously deduce its type in template substitution.
Explicitly defining that argument's type will resolve the issue:
f("world", std::initializer_list<int>{ 1, 2, 3 });
A very similar case is given (as an example of an error) on this cppreference page.

Passing templated reference-parameters to a thread

How could I make this working ?
#include <iostream>
#include <thread>
using namespace std;
int main()
{
auto thr = []<typename PrintType>( PrintType &p )
{
cout << p << endl;
};
string str = "hello world";
jthread jt( thr, ref( str ) );
}
I don't even understand what's the issue here.
This is what clang 13 on Windows says:
In file included from test.cpp:2:
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:55:9: error: no matching function for call to 'invoke'
_STD invoke(_STD move(_STD get<_Indices>(_Tup))...);
^~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\yvals_core.h:1385:20: note: expanded from macro '_STD'
#define _STD ::std::
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:62:17: note: in instantiation of function template specialization 'std::thread::_Invoke<std::tuple<(lambda at test.cpp:8:13), std::reference_wrapper<std::basic_string<char>>>, 0ULL, 1ULL>' requested here
return &_Invoke<_Tuple, _Indices...>;
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:302:19: note: in instantiation of function template specialization 'std::thread::_Start<(lambda at test.cpp:8:13) &, std::reference_wrapper<std::basic_string<char>>>' requested here
_Impl._Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
^
test.cpp:13:10: note: in instantiation of function template specialization 'std::jthread::jthread<(lambda at test.cpp:8:13) &, std::reference_wrapper<std::basic_string<char>>, 0>' requested here
jthread jt( thr, ref( str ) );
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\type_traits:1482:19: note: candidate template ignored: substitution failure [with _Callable = (lambda at test.cpp:8:13), _Ty1 = std::reference_wrapper<std::basic_string<char>>, _Types2 = <>]: no matching function for call to '_Call'
_CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept(
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\type_traits:1476:19: note: candidate function template not viable: requires single argument '_Obj', but 2 arguments were provided
_CONSTEXPR17 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)()))
^
1 error generated.
The problem here is kinda unsolvable as long as we insist on passing thr lambda to jthread constructor. This snippet
auto thr = []<typename PrintType>( PrintType &p )
{
cout << p << endl;
};
string str = "hello world";
jthread jt(thr, str);
is going to fail, because you can't bind non-const reference to a temporary resulting within jthread constructor (Note: const PrintType& hp would work, but I assume, it would not be what OP wants).
std::ref would work with non-templated lambda:
auto thr = [](std::string& p)
{
std::cout << p << std::endl;
};
std::string str = "hello world";
std::thread jt( thr, std::ref(str) );
But it won't work with templated lambda (becauseauto thr = [](auto& p) will just try to bind non-const lvalue reference to temporary object of reference_wrapper type).
The only solution I can think of is to pass lambda with closures directly to thread constructor:
auto thr = []<class Type>(Type& p)
{
std::cout << p << std::endl;
};
std::string str = "hello world";
std::thread jt([&str, &thr]() { thr(str); });
TLDR:
jthread jt(&decltype(thr)::operator()<std::string>, thr, ref(str));
The problem you are having is due to a substitution of PrintType by std::reference_wrapper, which is not recognised as a valid argument for operator<<. You expect the compiler to do an implicit conversion from std::reference_wrapper to std::string& when receiving it as an argument, but the compiler does not expect an std::string& there. It expects std::reference_wrapper.
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/thread: In instantiation of 'static std::thread std::jthread::_S_create(std::stop_source&, _Callable&&, _Args&& ...) [with _Callable = main()::<lambda(PrintType&)>&; _Args = {std::reference_wrapper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >}]':
As you can see, you don't end up with std::string& as an argument, but with a wrapper: std::reference_wrapper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >.
This code compiles:
#include <thread>
#include <iostream>
using namespace std;
int main()
{
auto thr = [](const std::string &p)
{
cout << p << endl;
};
string str = "hello world";
jthread jt(thr, ref( str ));
}
So, the logical solution would be to force the compiler to instantiate the template with the right type:
#include <thread>
#include <iostream>
#include <type_traits>
using namespace std;
int main()
{
auto thr = []<typename PrintType>(PrintType& p)
{
cout << p << endl;
};
string str = "hello world";
// explicitly instantiating via a pointer to member function
jthread jt(&decltype(thr)::operator()<std::string>, thr, ref(str));
}

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.

C++ bound function passed to a lambda

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

Compile error about std::future

Code like this:
#include <iostream>
#include <future>
#include <thread>
#include <unistd.h>
int foo(int n) {
n = n*1000;
sleep(1);
return n;
}
int main(void) {
std::packaged_task<int (int)> task(std::bind(foo, 3));
std::future<int> f(task.get_future());
std::thread trd(std::move(task));
std::cout << f.get() << std::endl;
return 0;
}
gcc report:
In file included from /usr/include/c++/4.8.2/future:38:0,
from a.cpp:2:
/usr/include/c++/4.8.2/functional: In instantiation of ‘struct std::_Bind_simple<std::packaged_task<int(int)>()>’:
/usr/include/c++/4.8.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = std::packaged_task<int(int)>; _Args = {}]’
a.cpp:16:33: required from here
/usr/include/c++/4.8.2/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::packaged_task<int(int)>()>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.8.2/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::packaged_task<int(int)>()>’
_M_invoke(_Index_tuple<_Indices...>)
^
make: *** [a] Error 1
My gcc version is 4.8.2 on fedora 20
The function foo is declared as:
int foo(int);
It has the function type int(int) (taking a parameter int and returning int).
However, the resulting callable returned by std::bind when you bind 3 to the first parameter has a different function type: int(), e.g.:
auto func = std::bind(foo, 3) // Bind 3 to the first parameter.
func(); // Calling func requires no parameter.
Solution
The template parameter specified when declaring the std::packaged_task should be specified as int(), e.g.:
std::packaged_task<int()> task{std::bind(foo, 3)};
Alternatively don't bind the parameter to 3 when constructing the std::packaged_task, instead supply it directly when creating the std::thread object:
std::packaged_task<int(int)> task{foo}; // Don't bind 3
auto f = task.get_future();
std::thread trd{std::move(task), 3}; // Supply 3 here instead.
std::cout << f.get() << std::endl;
Furthermore
Make sure to call trd.join() before returning from function main.
When using std::thread also use the sleep function from the Standard Library instead of the non-portable sleep, e.g.:
std::this_thread::sleep_for(std::chrono::seconds(1));
Also when using std::move you should include the header <utility> in case the other headers don't include it.