Problem Statement - tl;dr
Add numbers to a vector, then output them
Details
My intention was to make a class Foo, that contained a std::vector<int> that I could populate in a thread-safe manner. I created an AddValue method to allow adding values to that vector keeping thread-safety in mind.
std::mutex mt;
class Foo
{
public:
void AddValue(int i)
{
std::lock_guard<std::mutex> lg{ mt };
values.push_back(i);
}
void PrintValues() const
{
for (int i : values)
{
std::cout << i << " ";
}
}
private:
std::vector<int> values;
};
I then made a free function that I could use to create a thread, without any knowledge of the internals of Foo.
void Func(Foo& foo, int t)
{
for (int i = 0; i < t; i++)
{
foo.AddValue(i);
}
}
My intention was to add the following values to the vector (in whatever order they ended up due to the thread timing)
{3, 2, 2, 1, 1, 1, 0, 0, 0, 0}
Here is a quick test to see if that was working.
int main()
{
Foo foo;
std::vector<std::thread> threads;
for (int i = 1; i < 5; ++i)
{
threads.emplace_back(Func, foo, i);
}
std::for_each(begin(threads), end(threads), [](std::thread& t){ t.join(); });
foo.PrintValues();
}
Problem
The above code won't compile
This is the error message
In file included from /usr/include/c++/4.9/mutex:42:0,
from 3:
/usr/include/c++/4.9/functional: In instantiation of 'struct std::_Bind_simple<void (*(Foo, int))(Foo&, int)>':
/usr/include/c++/4.9/thread:140:47: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(Foo&, int); _Args = {Foo&, int&}]'
/usr/include/c++/4.9/ext/new_allocator.h:120:4: required from 'void __gnu_cxx::new_allocator< <template-parameter-1-1> >::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {void (&)(Foo&, int), Foo&, int&}; _Tp = std::thread]'
/usr/include/c++/4.9/bits/alloc_traits.h:253:4: required from 'static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {void (&)(Foo&, int), Foo&, int&}; _Alloc = std::allocator<std::thread>; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]'
/usr/include/c++/4.9/bits/alloc_traits.h:399:57: required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {void (&)(Foo&, int), Foo&, int&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]'
/usr/include/c++/4.9/bits/vector.tcc:97:40: required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {void (&)(Foo&, int), Foo&, int&}; _Tp = std::thread; _Alloc = std::allocator<std::thread>]'
44:42: required from here
/usr/include/c++/4.9/functional:1665:61: error: no type named 'type' in 'class std::result_of<void (*(Foo, int))(Foo&, int)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.9/functional:1695:9: error: no type named 'type' in 'class std::result_of<void (*(Foo, int))(Foo&, int)>'
_M_invoke(_Index_tuple<_Indices...>)
^
I don't quite understand that error message. Am I not adding the threads to the vector threads correctly?
You have to wrap the foo in a std::ref. Threads don't allow things to be passed by reference without that wrapper.
Related
I have a strange compilation problem that I can't understand.
//I know, you should never derive from the STL Library
template<class T>
class SharedClass : private shared_ptr<T>
{
public:
template<class T2>
SharedClass(T2&& t2) :
shared_ptr<T>(make_shared<T>(move(t2)))
{}
virtual ~SharedClass()
{}
};
class A
{
public:
typedef function<void(SharedClass<A>)> Callback;
A(Callback callback)
{ }
};
main.cpp
SharedClass<A> shared([](SharedClass<A>){ });
Compile Log:
In file included from /usr/include/x86_64-linux-gnu/c++/7/bits/c++allocator.h:33:0,
from /usr/include/c++/7/bits/allocator.h:46,
from /usr/include/c++/7/string:41,
from /usr/include/c++/7/bits/locale_classes.h:40,
from /usr/include/c++/7/bits/ios_base.h:41,
from /usr/include/c++/7/ios:42,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from main.cpp:9:
/usr/include/c++/7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = A; _Args = {SharedClass<A>}; _Tp = A]’:
/usr/include/c++/7/bits/alloc_traits.h:475:4: required from ‘static void std::allocator_traits<std::allocator<_CharT>>::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = A; _Args = {SharedClass<A>}; _Tp = A; std::allocator_traits<std::allocator<_CharT>>::allocator_type = std::allocator<A>]’
/usr/include/c++/7/bits/shared_ptr_base.h:526:39: required from ‘std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {SharedClass<A>}; _Tp = A; _Alloc = std::allocator<A>; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’ /usr/include/c++/7
/bits/shared_ptr_base.h:637:4: required from ‘std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = A; _Alloc = std::allocator<A>; _Args = {SharedClass<A>}; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’
/usr/include/c++/7/bits/shared_ptr_base.h:1295:35: required from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>; _Args = {SharedClass<A>}; _Tp = A; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’
/usr/include/c++/7/bits/shared_ptr.h:344:64: required from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>; _Args = {SharedClass<A>}; _Tp = A]’
/usr/include/c++/7/bits/shared_ptr.h:690:14: [ skipping 9 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/c++/7/bits/shared_ptr_base.h:1295:35: required from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>; _Args = {main()::<lambda(SharedClass<A>)>}; _Tp = A; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’
/usr/include/c++/7/bits/shared_ptr.h:344:64: required from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>; _Args = {main()::<lambda(SharedClass<A>)>}; _Tp = A]’ /usr/include/c++/7/bits/shared_ptr.h:690:14: required from ‘std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = A; _Alloc = std::allocator<A>; _Args = {main()::<lambda(SharedClass<A>)>}]’
/usr/include/c++/7/bits/shared_ptr.h:706:39: required from ‘std::shared_ptr<_Tp> std::make_shared(_Args&& ...) [with _Tp = A; _Args = {main()::<lambda(SharedClass<A>)>}]’
main.cpp:21:33: required from ‘SharedClass<T>::SharedClass(T2&&) [with T2 = main()::<lambda(SharedClass<A>)>; T = A]’
main.cpp:39:48: required from here
/usr/include/c++/7/ext/new_allocator.h:136:4: error: no matching function for call to ‘A::A(SharedClass)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:33:5: note: candidate: A::A(A::Callback)
A(Callback callback)
^ main.cpp:33:5: note: no known conversion for argument 1 from ‘SharedClass’ to ‘A::Callback {aka std::function)>}’
main.cpp:28:7: note: candidate: constexpr A::A(const A&)
class A
^ main.cpp:28:7: note: no known conversion for argument 1 from ‘SharedClass’ to ‘const A&’
main.cpp:28:7: note: candidate: constexpr A::A(A&&)
main.cpp:28:7: note: no known conversion for argument 1 from ‘SharedClass’ to ‘A&&’
If I change the constructor of the SharedClass class like this SharedClass (T2 t2) it compiles.
As your lambda takes its parameters by value it needs to be able to create copies of those parameters, it does this by calling the move constructor. As you have defined a templated constructor with the same signature as the move constructor the compiler attempts to use it as a move constructor. Adding default copy (for completeness) and move constructors fixes the issue:
SharedClass(const SharedClass&) = default;
SharedClass(SharedClass&&) = default;
Your existing constructor doesn't work as a move constructor because there is no constructor for A which takes a SharedClass<A> parameter so make_shared<A> doesn't compile when passed a SharedClass<A> parameter.
this code fails to compile:
Class declaration:
class threadController
{
private:
static std::forward_list<std::thread> threadList;
static std::mutex mutexThreadList;
public:
static void startAndAddThreadToList(int argc, char * argv []);
};
Class definition:
std::forward_list<std::thread> threadController::threadList;
std::mutex threadController::mutexThreadList;
void threadController::startAndAddThreadToList(int argc, char * argv [])
{
// execute now the thread to avoid a delayed start because of the mutex lock
std::thread threadInstance(threadCalculateOneInstrument, argc, argv);
mutexThreadList.lock();
threadList.push_front(threadInstance);
mutexThreadList.unlock();
}
This is the compiler error:
/usr/local/include/c++/4.9.1/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {const std::thread&}; _Tp = std::thread]’:
/usr/local/include/c++/4.9.1/bits/alloc_traits.h:253:4: required from ‘static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]’
/usr/local/include/c++/4.9.1/bits/alloc_traits.h:399:57: required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/local/include/c++/4.9.1/bits/forward_list.h:357:42: required from ‘std::_Fwd_list_base<_Tp, _Alloc>::_Node* std::_Fwd_list_base<_Tp, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::thread&}; _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::_Fwd_list_base<_Tp, _Alloc>::_Node = std::_Fwd_list_node<std::thread>]’
/usr/local/include/c++/4.9.1/bits/forward_list.tcc:71:64: required from ‘std::_Fwd_list_node_base* std::_Fwd_list_base<_Tp, _Alloc>::_M_insert_after(std::_Fwd_list_base<_Tp, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::thread&}; _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::_Fwd_list_base<_Tp, _Alloc>::const_iterator = std::_Fwd_list_const_iterator<std::thread>]’
/usr/local/include/c++/4.9.1/bits/forward_list.h:803:9: required from ‘void std::forward_list<_Tp, _Alloc>::push_front(const _Tp&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>]’
../source/threadController.cpp:27:38: required from here
/usr/local/include/c++/4.9.1/ext/new_allocator.h:120:4: error: use of deleted function ‘std::thread::thread(const std::thread&)’
My intention is to implement a thread list. The threads run with indefinite execution time. A "control" thread is checking each 10 seconds the threads in the list. If a thread finished the thread function detach() is called for this thread in order to release the resources.
It is not permitted to copy std::thread objects, you can use emplace like this:
threadList.emplace_front(threadCalculateOneInstrument, argc, argv);
See: std::forward_list::emplace_front().
std::threads are not copyable, you can either use emplace_front() as suggested by Galik, or insert rvalues (in this case move constructor will be invoked):
threadList.push_front(std::thread(threadCalculateOneInstrument, argc, argv));
This can be useful if you have a function which returns std::thread, so emplace_front() is not applicable:
std::thread createThread() {....}
threadList.push_front(createThread());
I'm new in C++ , i use G++ compiler (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1
i try to implement undirected wieghted Graph. by two classes Edges and Graph. but the compiler gives me this error
the compiler gives this error
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...)
[with _Up = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Tp =
UNDIR_W_EDGE]':
/usr/include/c++/4.8/bits/alloc_traits.h:254:4: required from 'static typename
std::enable_ifAlloc>::_construct_helper<_Tp,
_Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&&
...) [with _Tp = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Alloc =
std::allocator; typename
std::enable_ifAlloc>::_construct_helper<_Tp,
_Args>::value, void>::type = void]'
/usr/include/c++/4.8/bits/alloc_traits.h:393:57: required from 'static decltype (_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits::construct::__args)...))
std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...)
[with _Tp = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Alloc =
std::allocator; decltype (_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits::construct::__args)...)) =
]'
/usr/include/c++/4.8/bits/stl_vector.h:906:34: required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp
= UNDIR_W_EDGE; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = UNDIR_W_EDGE]'
../src/GRAPH.h:31:5: required from 'void GRAPH::addEdge(const Edge&) [with Edge = UNDIR_W_EDGE]'
../src/main.cpp:32:13: required from here
/usr/include/c++/4.8/ext/new_allocator.h:120:4: error: no matching function for call to 'UNDIR_W_EDGE::UNDIR_W_EDGE(const UNDIR_W_EDGE&)'
{ ::new((void *)__p) _Up(std::forward<Args>(_args)...); }
The Code
GRAPH.h file
#include "vector"
template <typename Edge>
class GRAPH {
private:
// Implementation-dependent code
int Vcnt;
int Ecnt;
std::vector<std::vector< Edge > > adj;
public:
GRAPH(int x):Vcnt(x),Ecnt(0) {
adj.resize(Vcnt);
}
virtual ~GRAPH();
virtual int V() const;
virtual int E() const;
virtual void addEdge(const Edge &e){
adj[e.V()].push_back(e);
adj[e.W()].push_back(e);
Ecnt++;
};
virtual std::vector< Edge > adjIterator(int) const;
};
UNDIRWEDGE.h file
class UNDIR_W_EDGE {
int v,w;
float weight;
public:
UNDIR_W_EDGE(int v, int w, float weight);
UNDIR_W_EDGE(UNDIR_W_EDGE &);
virtual ~UNDIR_W_EDGE();
virtual int V()const;
virtual int W()const;
virtual float WEIGHT()const;
virtual int CompareTo(UNDIR_W_EDGE e)const;
};
in UNDIRWEDGE.cpp
inline int UNDIR_W_EDGE::CompareTo(UNDIR_W_EDGE e)const{
if(this->weight > e.weight) return 1;
else if (this->weight < e.weight)return -1;
else return 0;
}
in main.cpp
GRAPH<UNDIR_W_EDGE> g(10);
UNDIR_W_EDGE e(0,7,0.0);
g.addEdge(e);
You don't have a copy constructor for UNDIR_W_EDGE.
The copy constructor is required inside std::vector<UNDIR_W_EDGE>, as well as in CompareTo which takes its argument by value (for some reason).
You do have this:
UNDIR_W_EDGE(UNDIR_W_EDGE &);
Presumably you intended for it to be:
UNDIR_W_EDGE(const UNDIR_W_EDGE&);
I have this minimal not-working example of code
#include <future>
int main()
{
auto intTask = std::packaged_task<int()>( []()->int{ return 5; } );
std::packaged_task<void()> voidTask{ std::move(intTask) };
}
Why doesn't it compile (on gcc 4.8.1)? I suspect, the reason is, that std::packaged_task stores the lambda internally inside an std::function which needs a CopyConstructible argument. However, std::packaged_task is move-only. Is this a bug? What does the standard say about it? In my opinion std::packaged_task should not need a CopyConstructible argument, but a MoveConstructible argument should be enough.
By the way, when I replace std::packaged_task<int()> by std::packaged_task<void()> everything compiles fine.
GCC 4.8.1 is giving me this error message:
In file included from /usr/include/c++/4.6/future:38:0,
from ../cpp11test/main.cpp:160:
/usr/include/c++/4.6/functional: In static member function 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = std::packaged_task<int()>, std::false_type = std::integral_constant<bool, false>]':
/usr/include/c++/4.6/functional:1652:8: instantiated from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = std::packaged_task<int()>]'
/usr/include/c++/4.6/functional:2149: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::packaged_task<int()>, _Res = void, _ArgTypes = {}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<void()>::_Useless]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:410:4: instantiated from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:518:8: instantiated from 'std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:987:35: instantiated from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr.h:317:64: instantiated from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>]'
/usr/include/c++/4.6/bits/shared_ptr.h:535:39: instantiated from 'std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}]'
/usr/include/c++/4.6/bits/shared_ptr.h:551:42: instantiated from 'std::shared_ptr<_Tp1> std::make_shared(_Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Args = {std::packaged_task<int()>}]'
/usr/include/c++/4.6/future:1223:66: instantiated from 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(_Fn&&) [with _Fn = std::packaged_task<int()>, _Res = void, _ArgTypes = {}]'
../cpp11test/main.cpp:165:61: instantiated from here
/usr/include/c++/4.6/functional:1616:4: error: use of deleted function 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = int, _ArgTypes = {}, std::packaged_task<_Res(_ArgTypes ...)> = std::packaged_task<int()>]'
/usr/include/c++/4.6/future:1244:7: error: declared here
UPDATE: I have written the following test program. It seems to support the assumption that the reason is missing CopyConstructability. Again, what are the requirements on the type of the object from which an std::packaged_task may be constructed?
#include <future>
struct Functor {
Functor() {}
Functor( const Functor & ) {} // without this line it doesn't compile
Functor( Functor && ) {}
int operator()(){ return 5; }
};
int main() {
auto intTask = std::packaged_task<int()>( Functor{} );
}
Indeed, packaged_task only has a moving constructor (30.6.9/2):
template <class F> explicit packaged_task(F&& f);
However, your problem is the explicit constructor. So write it like this:
std::packaged_task<int()> pt([]() -> int { return 1; });
Complete example:
#include <future>
#include <thread>
int main()
{
std::packaged_task<int()> intTask([]() -> int { return 5; } );
auto f = intTask.get_future();
std::thread(std::move(intTask)).detach();
return f.get();
}
No. You just can't move a packaged_task<int ()> into a packaged_task<void ()>. These types a unrelated and cannot be move-assigned or move-constructed from each other. If you for some reason really want to do that you can "swallow" the result of the int () like this
The standard (as of N3690) doesn't state anything explicitly about the requirements of the type F in
template <class R, class... ArgTypes>
template <class F>
packaged_task<R(ArgTypes...)>::packaged_task(F&& f);
(see 30.6.9.1) However, it states that
Invoking a copy of f shall behave the same as invoking f.
and that this call can throw
any exceptions thrown by the copy or move constructor of f, or std::bad_alloc if memory
for the internal data structures could not be allocated.
This implicitly implies that the type F must be at least MoveConstructible, or CopyConstructible, if an lvalue reference is handed to the function.
Hence, it's not a bug, it's just not specified that precisely. To solve the problem of putting a std::packaged_task<int()> into a std::packaged_task<void()> just wrap the first into a shared_ptr like this:
#include <future>
#include <memory>
int main()
{
auto intTask = std::make_shared<std::packaged_task<int()>>(
[]()->int{ return 5; } );
std::packaged_task<void()> voidTask{ [=]{ (*intTask)(); } };
}
The purpose is to execute CVS890Executor::do_full_frame when calling the m_callback_fn within CDevVS890.
Following is the incriminated code:
"CDevVS890.h"
typedef std::tr1::function<void (void* frame, int len)> DoFrameFn;
class CDevVS890
{
public:
CDevVS890();
void receive();
DoFrameFn m_callback_fn;
}
"CDevVS890.cpp"
void CDevVS890::receive()
{
...
m_callback_fn((void*)frame, (int)len);
}
/*----------------------------------------------------------------------*/
"CVS890Executor.h"
class CVS890Executor
{
public:
CVS890Executor();
private:
void hookup_to_DevVS890();
void do_full_frame( void* frame, int len );
}
"CVS890Executor.cpp"
CVS890Executor::CVS890Executor()
{
hookup_to_DevVS890();
}
void CVS890Executor::hookup_to_DevVS890()
{
m_pDevVS890 = new CDevVS890();
m_pDevVS890->m_callback_fn =
std::tr1::bind(&CVS890Executor::do_full_frame, this, _1);
}
void CVS890Executor::do_full_frame(void* frame, int len)
{
...
}
The errors are multiple and very difficult to read:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1/functional:56,
from ../../src/Common/CDevVS890.h:17,
from CVS890Executor.h:13,
from CVS890Executor.cpp:8:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional: In member function âtypename std::tr1::result_of<_Functor(typename std::tr1::result_of 0)>(_Bound_args, std::tr1::tuple<_UElements ...>)>::type ...)>::type std::tr1::_Bind<_Functor(_Bound_args ...)>::__call(const std::tr1::tuple<_UElements ...>&, std::tr1::_Index_tuple<_Indexes ...>) [with _Args = void*&, int&, int ..._Indexes = 0, 1, _Functor = std::tr1::_Mem_fn, _Bound_args = CVS890Executor*, std::tr1::_Placeholder<1>]â:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1191: instantiated from âtypename std::tr1::result_of<_Functor(typename std::tr1::result_of 0)>(_Bound_args, std::tr1::tuple<_UElements ...>)>::type ...)>::type std::tr1::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) [with _Args = void*, int, _Functor = std::tr1::_Mem_fn, _Bound_args = CVS890Executor*, std::tr1::_Placeholder<1>]â
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1668: instantiated from âstatic void std::tr1::_Function_handler::_M_invoke(const std::tr1::_Any_data&, _ArgTypes ...) [with _Functor = std::tr1::_Bind(CVS890Executor*, std::tr1::_Placeholder<1>)>, _ArgTypes = void*, int]â
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:2005: instantiated from âstd::tr1::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(_ArgTypes ...)>::Useless>::_type) [with _Functor = std::tr1::_Bind(CVS890Executor*, std::tr1::_Placeholder<1>)>, _Res = void, _ArgTypes = void*, int]â
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1885: instantiated from âtypename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(ArgTypes ...)>&>::_type std::tr1::function<_Res(_ArgTypes ...)>::operator=(_Functor) [with _Functor = std::tr1::_Bind(CVS890Executor*, std::tr1::_Placeholder<1>)>, _Res = void, _ArgTypes = void*, int]â
CVS890Executor.cpp:115: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1137: error: no match for call to â(std::tr1::_Mem_fn) (CVS890Executor*&, void*&)â
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:546: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void, _Class = CVS890Executor, _ArgTypes = void*, int]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:551: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void, _Class = CVS890Executor, _ArgTypes = void*, int]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1137: error: return-statement with a value, in function returning 'void'
make: * [CVS890Executor.o] Error 1
Any idea what's wrong with this?
Cheers
You forgot about the second argument. Your call of bind function should be like this:
std::tr1::bind(&CVS890Executor::do_full_frame, this, _1, _2);
// ^^
In CVS890Executor::hookup_to_DevVS890(), you are not binding any arguments to the member function do_full_frame.
You are also trying to assign the return value of the function to m_callback_fn but do_full_frame() is declared to return void (no return value).