Im trying to create a simple wrapper to be used by my application when creating threads in lew of std::thread.
The only purpose of using this app thread wrapper is to ensure some code gets invoked on every spawned thread consistently. I thought this would be trivial, but the std::thread constructor and argument passing is rather complex and Im getting very cryptic build errors here.
This is a simple example of what I'm trying to do:
#include <thread>
class AppThread : public std::thread
{
template< class Function, class... Args >
static void wrap( Function&& f, Args&&... args )
{
//Some code
f( std::forward<Args>( args )... );
}
public:
template< class Function, class... Args >
explicit AppThread( Function&& f, Args&&... args ) : std::thread( AppThread::wrap<Function,Args...>,
std::forward<Function>( f ), std::forward<Args>( args )... )
{}
};
void runA() {}
void runB( int x ) {}
main()
{
AppThread thread1 = AppThread( runA );
//AppThread thread2 = AppThread( runB, 5 );
}
I'd like to be able to drop in AppThread wherever std:thread is being used, so extending and overriding the constructor seems like the best approach. But passing those arguments through to my wrapped method causes this cascade of errors ( gcc 7.2 )
In file included from thread_wrap.cpp:1:0:
gcc-7.2.0/include/c++/7.2.0/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’:
gcc-7.2.0/include/c++/7.2.0/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130: required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41: required from here
gcc-7.2.0/include/c++/7.2.0/thread:240:2: error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_M_invoke(std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_Indices)’
operator()()
^~~~~~~~
gcc-7.2.0/include/c++/7.2.0/thread:231:4: note: candidate: template<long unsigned int ..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind ...>) [with long unsigned int ..._Ind = {_Ind ...}; _Tuple = std::tuple<void (*)(void (&)()), void (*)()>]
_M_invoke(_Index_tuple<_Ind...>)
^~~~~~~~~
gcc-7.2.0/include/c++/7.2.0/thread:231:4: note: template argument deduction/substitution failed:
gcc-7.2.0/include/c++/7.2.0/thread: In substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’:
gcc-7.2.0/include/c++/7.2.0/thread:240:2: required from ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’
gcc-7.2.0/include/c++/7.2.0/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130: required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41: required from here
gcc-7.2.0/include/c++/7.2.0/thread:233:29: error: no matching function for call to ‘__invoke(std::__tuple_element_t<0, std::tuple<void (*)(void (&)()), void (*)()> >, std::__tuple_element_t<1, std::tuple<void (*)(void (&)()), void (*)()> >)’
-> decltype(std::__invoke(_S_declval<_Ind>()...))
~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
In file included from gcc-7.2.0/include/c++/7.2.0/tuple:41:0,
from gcc-7.2.0/include/c++/7.2.0/bits/unique_ptr.h:37,
from gcc-7.2.0/include/c++/7.2.0/memory:80,
from gcc-7.2.0/include/c++/7.2.0/thread:39,
from thread_wrap.cpp:1:
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: note: candidate: template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)
__invoke(_Callable&& __fn, _Args&&... __args)
^~~~~~~~
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: note: template argument deduction/substitution failed:
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h: In substitution of ‘template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = void (*)(void (&)()); _Args = {void (*)()}]’:
gcc-7.2.0/include/c++/7.2.0/thread:233:29: required by substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’
gcc-7.2.0/include/c++/7.2.0/thread:240:2: required from ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’
gcc-7.2.0/include/c++/7.2.0/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130: required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41: required from here
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: error: no type named ‘type’ in ‘struct std::__invoke_result<void (*)(void (&)()), void (*)()>’
Could definitely use some insight here!
Thanks
Here's an example of what I think Sam is driving at. As you can see, it is only a few lines of code so I'll leave it at that.
#include <iostream>
#include <thread>
#include <functional>
void preamble (void) { std::cout << "preamble\n"; }
template <class F, class ... Args> std::thread ThreadWrapper (F f, Args&& ... args)
{
return std::thread ([f, args...] () { preamble (); f (std::forward <Args...> (args...)); });
};
int main()
{
std::thread t = ThreadWrapper ([] (std::string s) { std::cout << s << "\n"; }, "42");
t.join ();
}
Output:
preamble
42
Live demo
I figured this out when I woke up this morning :)
Since std::thread decays all arguments it passes to the function, by the time it calls my wrap method the arguments are the decayed types. However, when I'm passing the template args to wrap<> it gets the undecayed types:
std::thread( AppThread::wrap<Function,Args...>,
Solution is simple, I need decay the types before instantiation the template wrap method:
std::thread( AppThread::wrap<std::decay_t<Function>,std::decay_t<Args>...>,
Related
This is my (simplified) code where I'm trying to call async forwarding arguments:
template<typename Ret, typename ... Args>
class CallbackAsyncTask {
public:
CallbackAsyncTask() {
}
virtual ~CallbackAsyncTask() = default;
void execute( Args&& ... args ) {
execute(&CallbackAsyncTask<Ret, Args...>::onBackground, this, std::forward<Args>(args)...);
}
protected:
virtual Ret onBackground( Args& ... args ) = 0;
template<typename Fn, typename ... Argss>
void execute( Fn&& fn, Argss&& ... args ) noexcept(false) {
std::async(std::launch::async, std::forward<Fn>(fn), std::forward<Argss>(args)...);
}
};
class Child: public CallbackAsyncTask<int, int> {
public:
virtual int onBackground( int& i ) {
return i;
}
};
int main() {
Child c;
c.execute(15);
return 0;
}
I get this error:
../main.cpp: In instantiation of ‘void CallbackAsyncTask<Ret, Args>::execute(Fn&&, Argss&& ...) [with Fn = int (CallbackAsyncTask<int, int>::*)(int&); Argss = {CallbackAsyncTask<int, int>* const, int}; Ret = int; Args = {int}]’:
../main.cpp:27:98: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Args&& ...) [with Ret = int; Args = {int}]’
../main.cpp:46:17: required from here
../main.cpp:33:90: error: no matching function for call to ‘async(std::launch, int (CallbackAsyncTask<int, int>::*)(int&), CallbackAsyncTask<int, int>* const, int)’
std::async(std::launch::async, std::forward<Fn>(fn), std::forward<Argss>(args)...);
^
../main.cpp:33:90: note: candidates are:
In file included from ../main.cpp:13:0:
/usr/include/c++/4.8.2/future:1532:5: note: template<class _Fn, class ... _Args> std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^
/usr/include/c++/4.8.2/future:1532:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.8.2/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = int (CallbackAsyncTask<int, int>::*)(int&); _Args = {CallbackAsyncTask<int, int>* const, int}]’:
../main.cpp:33:90: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Fn&&, Argss&& ...) [with Fn = int (CallbackAsyncTask<int, int>::*)(int&); Argss = {CallbackAsyncTask<int, int>* const, int}; Ret = int; Args = {int}]’
../main.cpp:27:98: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Args&& ...) [with Ret = int; Args = {int}]’
../main.cpp:46:17: required from here
/usr/include/c++/4.8.2/future:1532:5: error: no type named ‘type’ in ‘class std::result_of<int (CallbackAsyncTask<int, int>::*(CallbackAsyncTask<int, int>*, int))(int&)>’
../main.cpp: In instantiation of ‘void CallbackAsyncTask<Ret, Args>::execute(Fn&&, Argss&& ...) [with Fn = int (CallbackAsyncTask<int, int>::*)(int&); Argss = {CallbackAsyncTask<int, int>* const, int}; Ret = int; Args = {int}]’:
../main.cpp:27:98: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Args&& ...) [with Ret = int; Args = {int}]’
../main.cpp:46:17: required from here
/usr/include/c++/4.8.2/future:1552:5: note: template<class _Fn, class ... _Args> std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^
/usr/include/c++/4.8.2/future:1552:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.8.2/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {int (CallbackAsyncTask<int, int>::*)(int&), CallbackAsyncTask<int, int>* const, int}]’:
../main.cpp:33:90: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Fn&&, Argss&& ...) [with Fn = int (CallbackAsyncTask<int, int>::*)(int&); Argss = {CallbackAsyncTask<int, int>* const, int}; Ret = int; Args = {int}]’
../main.cpp:27:98: required from ‘void CallbackAsyncTask<Ret, Args>::execute(Args&& ...) [with Ret = int; Args = {int}]’
../main.cpp:46:17: required from here
/usr/include/c++/4.8.2/future:1552:5: error: no type named ‘type’ in ‘class std::result_of<std::launch(int (CallbackAsyncTask<int, int>::*)(int&), CallbackAsyncTask<int, int>*, int)>’
What I am missing? Compiler Gcc 4.8.3
The root cause is these two lines
virtual Ret onBackground( Args& ... args ) = 0;
virtual int onBackground( int& i )
When launching the task, the arguments are converted either directly or as if by the std::thread constructor. That one does decay_copy on the arguments when invoking the callable, so a non-const lvalue reference cannot bind to the argument.
Change the way onBackground accepts arguments. For instance, a const lvalue refernce works. See live.
This question already has answers here:
Start thread with member function
(5 answers)
Passing object by reference to std::thread in C++11
(4 answers)
Closed 3 years ago.
it is kinda late where I am now & I dont have much experience with threading so I may be overlooking something obvious... But I made a small example of what my error is :
Source Code :
#include <thread>
struct B {
/* Stuff */
};
struct A {
std::thread td;
A(const B& b) { td = std::thread(&A::f, b); }
void f(const B& b) { /* DO SOMETHING WTIH b */ }
};
int main() {
B b;
A a(b);
}
Compiling with g++ -c smallex.cpp and I dont really understand what my issue is here. I think it is pretty straight forward what I am trying to accomplish here..
In file included from smallex.cpp:1:0:
/usr/include/c++/7/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >’:
/usr/include/c++/7/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (A::*)(const B&); _Args = {const B&}]’
smallex.cpp:11:42: required from here
/usr/include/c++/7/thread:240:2: error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >::_M_invoke(std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >::_Indices)’
operator()()
^~~~~~~~
/usr/include/c++/7/thread:231:4: note: candidate: template<long unsigned int ..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind ...>) [with long unsigned int ..._Ind = {_Ind ...}; _Tuple = std::tuple<void (A::*)(const B&), B>]
_M_invoke(_Index_tuple<_Ind...>)
^~~~~~~~~
/usr/include/c++/7/thread:231:4: note: template argument deduction/substitution failed:
/usr/include/c++/7/thread: In substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’:
/usr/include/c++/7/thread:240:2: required from ‘struct std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >’
/usr/include/c++/7/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (A::*)(const B&); _Args = {const B&}]’
smallex.cpp:11:42: required from here
/usr/include/c++/7/thread:233:29: error: no matching function for call to ‘__invoke(std::__tuple_element_t<0, std::tuple<void (A::*)(const B&), B> >, std::__tuple_element_t<1, std::tuple<void (A::*)(const B&), B> >)’
-> decltype(std::__invoke(_S_declval<_Ind>()...))
~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/tuple:41:0,
from /usr/include/c++/7/bits/unique_ptr.h:37,
from /usr/include/c++/7/memory:80,
from /usr/include/c++/7/thread:39,
from smallex.cpp:1:
/usr/include/c++/7/bits/invoke.h:89:5: note: candidate: template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)
__invoke(_Callable&& __fn, _Args&&... __args)
^~~~~~~~
/usr/include/c++/7/bits/invoke.h:89:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/bits/invoke.h: In substitution of ‘template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = void (A::*)(const B&); _Args = {B}]’:
/usr/include/c++/7/thread:233:29: required by substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’
/usr/include/c++/7/thread:240:2: required from ‘struct std::thread::_Invoker<std::tuple<void (A::*)(const B&), B> >’
/usr/include/c++/7/thread:127:22: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (A::*)(const B&); _Args = {const B&}]’
smallex.cpp:11:42: required from here
/usr/include/c++/7/bits/invoke.h:89:5: error: no type named ‘type’ in ‘struct std::__invoke_result<void (A::*)(const B&), B>’
Can someone please help point me in the right direction?
Notes :
g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
I'm attempting to make a threadpool that takes any kind of function, and returns a future for any return value/exceptions that function may have. I'm doing this largely as an exercise to learn modern threading and some template programming. I tried basing my syntax loosely off how MSVC does std::function and futures.
Here's a minimum snippet of where my problem is:
#include <functional>
#include <future>
#include <utility>
#include <queue>
#include <memory>
using Job = std::function<void()>;
std::queue<std::unique_ptr<Job>> queue;
template<typename FuncType, typename... Args>
auto add(FuncType&& func, Args&&... args) ->std::future<decltype(func)(decltype(args)...)> {
auto task = std::packaged_task<decltype(func)(decltype(args)...)>(std::bind (std::forward<FuncType>(func), std::forward<Args>(args)...));
auto future = task.get_future();
queue.push(std::make_unique<Job>([task]() { task(); }));
return future;
}
void voidFunc(){};
int main()
{
add(voidFunc);
}
This fails to compile with the errors:
/usr/include/c++/4.9/future: In instantiation of 'class std::future<void (&())()>':
28:17: required from here
/usr/include/c++/4.9/future:697:7: error: function returning a function
get()
^
In instantiation of 'add(FuncType&&, Args&& ...)::<lambda()> [with FuncType = void (&)(); Args = {}]':
19:37: required from 'struct add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]::<lambda()>'
19:56: required from 'std::future<decltype (func)(decltype (args)...)> add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]'
28:17: required from here
19:52: error: passing 'const std::packaged_task<void (&())()>' as 'this' argument of 'void std::packaged_task<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) [with _Res = void (&)(); _ArgTypes = {}]' discards qualifiers [-fpermissive]
In instantiation of 'std::future<decltype (func)(decltype (args)...)> add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]':
28:17: required from here
19:36: error: use of deleted function 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = void (&)(); _ArgTypes = {}]'
In file included from 5:0:
/usr/include/c++/4.9/future:1413:7: note: declared here
packaged_task(const packaged_task&) = delete;
^
21:10: error: could not convert 'future' from 'std::future<void (&)()>' to 'std::future<void (&())()>'
In file included from 5:0:
/usr/include/c++/4.9/future: In instantiation of 'static std::__future_base::_Task_setter<_Res_ptr> std::__future_base::_S_task_setter(_Res_ptr&, _BoundFn&&) [with _Res_ptr = std::unique_ptr<std::__future_base::_Result<void (&)()>, std::__future_base::_Result_base::_Deleter>; _BoundFn = std::_Bind_simple<std::reference_wrapper<std::_Bind<void (*())()> >()>; typename _Res_ptr::element_type::result_type = void (&)()]':
/usr/include/c++/4.9/future:1318:70: required from 'void std::__future_base::_Task_state<_Fn, _Alloc, _Res(_Args ...)>::_M_run(_Args ...) [with _Fn = std::_Bind<void (*())()>; _Alloc = std::allocator<int>; _Res = void (&)(); _Args = {}]'
29:1: required from here
/usr/include/c++/4.9/future:539:57: error: could not convert 'std::ref(_Tp&) [with _Tp = std::_Bind_simple<std::reference_wrapper<std::_Bind<void (*())()> >()>]()' from 'std::reference_wrapper<std::_Bind_simple<std::reference_wrapper<std::_Bind<void (*())()> >()> >' to 'std::function<void (&())()>'
return _Task_setter<_Res_ptr>{ __ptr, std::ref(__call) };
^
In file included from /usr/include/c++/4.9/memory:81:0,
from /usr/include/c++/4.9/thread:40,
from /usr/include/c++/4.9/future:40,
from 5:
/usr/include/c++/4.9/bits/unique_ptr.h:764:5: error: 'typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = std::function<void()>; _Args = {add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]::<lambda()>}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<std::function<void()> >]', declared using local type 'add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]::<lambda()>', is used but never defined [-fpermissive]
make_unique(_Args&&... __args)
^
In function 'std::future<decltype (func)(decltype (args)...)> add(FuncType&&, Args&& ...) [with FuncType = void (&)(); Args = {}; decltype (func) = void (&)()]':
22:2: warning: control reaches end of non-void function [-Wreturn-type]
I think I have two problems here: I don't know how to properly use decltype to get the right function signature (I've also looked into invoke_result, but I wasn't having any luck there either), and I think I'm probably also not passing the packaged task to the queue properly.
How do I get the right function signature for the future and packaged task, and how do I properly pass the packaged task to a std::function on a queue (that will later be grabbed by another thread)?
Two problems:
1) The signature of packaged task should be
std::packaged_task<std::invoke_result_t<Func&&,Args&&...>(Args&&...)>. This uses invoke_result_t to compute the return type, but also passes the argument types to the packaged task.
2) Bigger problem: std::function requires that the function be copy constructable, which std::packaged_task is not. You'll have to create your own queue to hold the packaged tasks. I've implemented it before using a base class Task with a templated derived class to hold the packaged task.
Consider the following set of examples.
The function takeOnlyVoidFunction takes a function with zero arguments and simply executes it.
The function takeVariableArguments takes a variable number of arguments and executes the function using the arguments.
The function captureVariableArgs attempts to convert the second function into a lambda form that is acceptable by the first function, but it does not compile.
How can I make the function captureVariableArgs compile and exhibit the correct behavior of converting a function with a variable number of arguments into a closure with no arguments?
#include <stdio.h>
#include <functional>
void takeOnlyVoidFunction(std::function<void()> task) {
task();
}
template<typename _Callable, typename... _Args>
void takeVariableArguments(_Callable&& __f, _Args&&... __args) {
__f(__args...);
}
// How can I make this function compile?
template<typename _Callable, typename... _Args>
void captureVariableArgs(_Callable&& __f, _Args&&... __args) {
takeOnlyVoidFunction([=]() { __f(__args...);});
}
void normalFunction(int a, int b) {
printf("I am a normal function which takes params (%d,%d)\n", a, b);
}
int main() {
int a = 7;
int b = 8;
takeVariableArguments(normalFunction, a, b);
takeOnlyVoidFunction([=](){ normalFunction(a,b);});
captureVariableArgs(normalFunction, a, b);
}
I'm running gcc 4.9.2. Here is the compiler error I see.
g++ -std=c++11 Test.cc -o Test
Test.cc: In instantiation of ‘captureVariableArgs(_Callable&&, _Args&& ...)::<lambda()> [with _Callable = void (&)(int, int); _Args = {int&, int&}]’:
Test.cc:16:38: required from ‘struct captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’
Test.cc:16:50: required from ‘void captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]’
Test.cc:28:45: required from here
Test.cc:16:34: error: variable ‘__f’ has function type
takeOnlyVoidFunction([=]() { __f(__args...);});
^
Test.cc:16:34: error: variable ‘__f’ has function type
Test.cc: In instantiation of ‘struct captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’:
Test.cc:16:50: required from ‘void captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]’
Test.cc:28:45: required from here
Test.cc:16:34: error: field ‘captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>::<__f capture>’ invalidly declared function type
In file included from Test.cc:2:0:
/usr/include/c++/4.9/functional:2418:7: error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>; <template-parameter-2-2> = void; _Res = void; _ArgTypes = {}]’, declared using local type ‘captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’, is used but never defined [-fpermissive]
function<_Res(_ArgTypes...)>::
^
Update: A more minimal example demonstrating this problem.
#include <stdio.h>
// How can I make this function compile?
template<typename _Callable>
void captureVariableArgs(_Callable&& __f) {
takeOnlyVoidFunction( [=]{ __f(); } );
}
void normalFunction() {
printf("I am a normal function\n");
}
int main(){
captureVariableArgs(normalFunction);
}
As another potential workaround for GCC, instead of using a lambda, you could use std::bind:
template <typename F, typename... Args>
auto captureVariable(F&& f, Args&&... args)
{
return std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}
This works for me under GCC 4.9.3.
The code in the post compiles fine with the latest clang&MSVC compilers but all the gccs refuse to compile it. So it seems a bug in gcc. Nevertheless, I found a way to make gcc happy: just don't use an "universal reference" on the callable argument, like this:
template<typename _Callable, typename... _Args>
int captureVariableArgs(_Callable _f, _Args&&... _args) {
return takeOnlyVoidFunction([=]() { _f(_args...);});
}
I can't explain why gcc doesn't accept your version, though. I'm not familiar with gcc-style error reporting and can't extract the true cause from the error message. But I think the workaround is ok since I don't see any value in "universal reference" in this case. In fact, I don't see why you use it on the args either.
In a continuation from this question. I'm trying to bind a given function that returns something-other-than void to be able to simply call f() later. However the following code fails to compile on GCC 4.4. It compiles on VS 2010, but the resulting program crashes.
template<typename RetType>
void _hideRet(std::function<RetType ()> func, RetType * ret)
{
*ret = func();
}
template<typename FuncType, typename RetType, typename ParamType>
std::function<void ()> registerFunc(FuncType func, RetType * ret, ParamType param)
{
auto f = std::bind(func, std::forward<ParamType>(param));
return std::bind(_hideRet<RetType>, f, ret);
}
int myFunction(std::string text)
{
std::cout << text << std::endl;
return 42;
}
int main()
{
int ret = 0;
auto f = registerFunc(myFunction, &ret, "text");
f();
std::cout << ret << std::endl;
return 0;
}
GCC produces this crazy message:
In file included from /usr/include/c++/4.4/functional:70,
from func.cpp:4:
/usr/include/c++/4.4/tr1_impl/functional: In member function ‘typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args, std::is_bind_expression::value, (std::is_placeholder::value > 0)>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::__call(const std::tuple<_UElements ...>&, std::_Index_tuple<_Indexes ...>) [with _Args = , int ..._Indexes = 0, 1, _Functor = void (*)(std::function<int()>, int*), _Bound_args = std::_Bind<int (*(const char*))(std::string)>, int*]’:
/usr/include/c++/4.4/tr1_impl/functional:1191: instantiated from ‘typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args, std::is_bind_expression::value, (std::is_placeholder::value > 0)>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) [with _Args = , _Functor = void (*)(std::function<int()>, int*), _Bound_args = std::_Bind<int (*(const char*))(std::string)>, int*]’
/usr/include/c++/4.4/tr1_impl/functional:1668: instantiated from ‘static void std::_Function_handler<void(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Functor = std::_Bind<void (*(std::_Bind<int (*(const char*))(std::string)>, int*))(std::function<int()>, int*)>, _ArgTypes = ]’
/usr/include/c++/4.4/tr1_impl/functional:2005: instantiated from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::is_integral::value), std::function<_Res(_ArgTypes ...)>::_Useless>::__type) [with _Functor = std::_Bind<void (*(std::_Bind<int (*(const char*))(std::string)>, int*))(std::function<int()>, int*)>, _Res = void, _ArgTypes = ]’
func.cpp:16: instantiated from ‘std::function<void()> registerFunc(FuncType, RetType*, ParamType) [with FuncType = int (*)(std::string), RetType = int, ParamType = const char*]’
func.cpp:28: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid conversion from ‘int’ to ‘std::_M_clear_type*’
/usr/include/c++/4.4/tr1_impl/functional:1137: error: initializing argument 1 of ‘std::function<_Res(_ArgTypes ...)>::function(std::_M_clear_type*) [with _Res = int, _ArgTypes = ]’
I don't have enough knowledge of the inner STL workings to make anything out of that.
However while experimenting I found out that if I remove the second std::bind call from the registerFunc template like this:
template<typename FuncType, typename RetType, typename ParamType>
std::function<RetType ()> registerFunc(FuncType func, RetType *, ParamType param)
{
return std::bind(func, std::forward<ParamType>(param));
}
// in main
auto tmp = registerFunc(myFunction, &ret, "text");
auto f = std::bind(_hideRet<int>, tmp, &ret);
f();
The code works as expected both in VS and GCC. So my conclusion is that the problem is in calling std::bind(_hideRet<RetType>, ...) from within a template function. The question is why is that a problem? And more importantly how to fix this?
This is absolutely amazing, but replacing :
auto f = std::bind(func, std::forward<ParamType>(param));
return std::bind(_hideRet<RetType>, f, ret);
by :
std::function<RetType ()> f = std::bind(func, std::forward<ParamType>(param));
return std::bind(_hideRet<RetType>, f, ret);
under Visual Studio 2010 runs as expected (which is essentially what you did by moving the second bind out of registerFunc). I'm trying to make sense out of it, but until then, that seems like a workaround for your issue,