Compile error about std::future - c++

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.

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.

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

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

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

Why does this code fragment compile with VS2010 but not GCC 4.5.2?

#include <functional>
#include <memory>
#include <iostream>
using namespace std;
class Foo
{
public:
void Bar() { std::cout << "Foo::Bar" << std::endl; }
};
int main()
{
shared_ptr<Foo> foo(new Foo);
function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
return 0;
}
GCC objects to the second bind statement being assigned to the function object with the shared_ptr signature. Here is the error output.
/usr/include/c++/4.5/functional:2103|6|instantiated from
‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename
std::enable_if<(! std::is_integral<_Functor>::value),
std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor =
std::_Bind(std::_Placeholder<1>)>, _Res
= void, _ArgTypes = {std::shared_ptr}, typename std::enable_if<(!
std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes
...)>::_Useless>::type =
std::function)>::_Useless]’|
/home/craig/work/litd/test/main.cpp:29|97|instantiated from here|
/usr/include/c++/4.5/functional|1713|error: no match for call to
‘(std::_Bind(std::_Placeholder<1>)>)
(std::shared_ptr)’| ||=== Build finished: 1 errors, 0 warnings
===|
Edit:
More mystery, when I change the include headers to their tr1 equivalents, it does compile.
#include <tr1/functional>
#include <tr1/memory>
#include <iostream>
using namespace std::tr1;
class Foo
{
public:
void Bar() { std::cout << "Foo::Bar" << std::endl; }
};
int main()
{
shared_ptr<Foo> foo(new Foo);
function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
return 0;
}
It looks like a bug in g++'s implementation of std::function or maybe std::bind, depending on whether you can invoke the object returned by bind(&Foo::Bar, placeholders::_1) with foo; if this works:
auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(foo);
then it would seem that g++'s std::function implementation is incomplete. Otherwise, it would seem that the implementation of std::bind is incomplete.
[20.8.9.1.2] Function template bind states:
template<class F, class... BoundArgs>
unspecified bind(F&& f, BoundArgs&&... bound_args);
...
Returns: A forwarding call wrapper g with a weak result type (20.8.2). The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of::type)
[20.8.2] Requirements states:
Define INVOKE(f, t1, t2, ..., tN) as follows:
— (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
— ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
...
When binding &Foo::Bar, the returned "forwarding call wrapper" takes one argument, u1. Call its type U1. Further on in [20.8.9.1.2] it states that because the 1st template argument type in BoundArgs was the _1 placeholder type, the type V1 is U1&&.
Passing a std::shared_ptr<Foo> to the forwarding call wrapper returned by bind(&Foo::Bar, placeholders::_1) should be allowed because case 2 of [20.8.2] applies.
EDIT: I am using the same version of g++ as you, 4.5.2, on Windows (MinGW). For me, the following compiles just fine:
#include <functional>
#include <memory>
#include <iostream>
using namespace std;
class Foo
{
public:
void Bar() { std::cout << "Foo::Bar" << std::endl; }
};
int main()
{
shared_ptr<Foo> foo(new Foo);
function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
//function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(foo);
return 0;
}
It thus appears to be g++'s implementation of std::function that is to blame.
EDIT2: The following fails:
auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(std::shared_ptr<Foo>(foo));
SO7408263.cpp:19:31: error: no match for call to '(std::_Bind(std::_Placeholder<1>)>) (std::shared_ptr)'
Perhaps it's std::bind after all.
The function will expect ->* to be overloaded to use a pointer-to-member. I believe that shared_ptr does not provide this functionality. The TR1 specification might have mandated a specialization but the C++11 might not. In Visual Studio then the C++11 shared_ptr is defined to be their TR1 versions, which would explain the difference.

How to use bind1st and bind2nd?

I would like to learn how to use binding functions.
Here is the idea:
I have this function which takes to parameters:
void print_i(int t, std::string separator)
{
std::cout << t << separator;
}
And I would like to do:
std::vector<int> elements;
// ...
for_each(elements.begin(), elements.end(), std::bind2nd(print_i, '\n'));
But it does not work !
Here is what I get:
/usr/include/c++/4.3/backward/binders.h: In instantiation of ‘std::binder2nd<void ()(int, std::string)>’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/backward/binders.h:138: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:141: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:145: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:149: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:155: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:140: error: field ‘std::binder2nd<void ()(int, std::string)>::op’ invalidly declared function type
/usr/include/c++/4.3/backward/binders.h: In function ‘std::binder2nd<_Operation> std::bind2nd(const _Operation&, const _Tp&) [with _Operation = void ()(int, std::string), _Tp = char]’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/backward/binders.h:164: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/bits/stl_algo.h: In function ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _Funct = std::binder2nd<void ()(int, std::string)>]’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/bits/stl_algo.h:3791: error: no match for call to ‘(std::binder2nd<void ()(int, std::string)>) (int&)’
make: *** [all] Error 1
I could use functor, but it is quicker to use binding.
Thanks!
You need to use a Copyable/Refrencable object, the following works:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
void print_i(int t, std::string separator)
{
std::cout << t << separator;
}
int main()
{
std::vector<int> elements;
std::string delim = "\n";
for_each(elements.begin(),
elements.end(),
std::bind2nd(std::ptr_fun(&print_i),delim));
return 0;
}
Normally you can get the same effect by simply doing the following:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> elements;
std::copy(elements.begin(),
elements.end(),
std::ostream_iterator<int>(std::cout,"\n"));
return 0;
}
Also assuming you have access to TR1 in the STL you're using, its always best to revise/replace any uses of bind1st and bind2nd with std::bind
The argument to bind2nd must be an AdaptableBinaryFunction. A plain binary function does not fulfill this requirement (an adaptable function required typedefs for its return and argument types, a plain function type does not provide any typedefs). You could use std::bind which is probably the better choice anyway.
You need to do the following steps:
1. create a struct (or class) that inherits from std::binary_function
2. define your predicate function in the operator() member function of the struct created in step 1
3. use bind2nd to bind an appropriate value to the struct created in step 1
I have done all this in an example. You can read the article and download the complete code on the following link: bind and find
These functions are deprecated since C++11 and removed in C++17. As mentioned in one comment above, the better solution now is to use std::bind and the placeholders:
void callable(int a, int b);
auto f = std::bind1st(&callable, 42); // returns a 1-arg function
becomes:
// returns a 1-arg function
auto f = std::bind(&callable, 42, std::placeholders::_1);