I'm working on implementing a wrapper for std::thread that will allow me retrieve arbitrary return values after the thread is finished executing. While I am using C++11, I am using an older ARM architecture that does not support fully support atomic int's, which means that I can't use std::future, std::promise, std::packaged_task, and much of the stl threading functionality (I do get std::thread at least). I am testing with gcc 4.8.4.
While working on my implementation, I ran into this bug, which makes it impossible for me capture variadic template parameters with a lambda. Unfortunately, I can not upgrade my compiler to 4.9 at the moment.
I'm attempting to implement a workaround using std::bind, but am running into quite a few issues. I'm unsure if these are compiler bugs or implementation errors on my part. Here is the source:
#include <iostream>
#include <memory>
#include <thread>
#include <unistd.h>
#include <pthread.h>
class ConcurrentTaskBase
{
public:
ConcurrentTaskBase(int priority, const std::function<void()>& runTask)
: m_thread(),
m_active(true)
{
auto wrap = [this](int priority, const std::function<void()>& runTask)
{
//Unrelated pthread stuff that I commented out
// sched_param param{priority};
//
// int err = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
// if (err)
// cout << "failed to set new priority: " << err << endl;
runTask();
};
m_thread = std::thread(wrap, priority, runTask);
}
virtual ~ConcurrentTaskBase(void)
{
waitForCompletion();
}
void waitForCompletion(void)
{
if (m_active)
{
m_thread.join();
m_active = false;
}
}
private:
std::thread m_thread;
bool m_active;
};
template<class R, class... ArgTypes>
class ConcurrentTask;
template<class R, class... ArgTypes>
class ConcurrentTask<R(ArgTypes...)> : public ConcurrentTaskBase
{
public:
ConcurrentTask(int priority, const std::function<R(ArgTypes...)>& task, ArgTypes&&... args)
: ConcurrentTaskBase(priority, bindTask(task, std::forward<ArgTypes>(args)...))
{}
std::shared_ptr<R> getReturn(void) noexcept
{
waitForCompletion();
return m_storage;
};
private:
static std::function<void(void)> bindTask(const std::function<R(ArgTypes...)>& task, ArgTypes&&... args)
{
auto action = [task](ArgTypes&&... args) -> void
{
//Eventually m_storage = std::make_shared<R>(task(std::forward<ArgTypes>(args)...)); after bugs are fixed
task(std::forward<ArgTypes>(args)...);
return;
};
std::function<void(void)> bound = std::bind(action, std::forward<ArgTypes>(args)...);
return bound;
};
std::shared_ptr<R> m_storage;
};
int testFunction(int val)
{
std::cout << "Was given " << val << std::endl;
return val + 10;
}
int main()
{
ConcurrentTask<int(int)> task(20, testFunction, 5);
// shared_ptr<int> received = task.getReturn();
// testFunction(*received);
return 0;
}
And here is my compiler output:
16:31:00 **** Incremental Build of configuration Debug for project TestLinuxMint ****
make all
Building file: ../src/TestLinuxMint.cpp
Invoking: GCC C++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -pthread -c -fmessage-length=0 -MMD -MP -MF"src/TestLinuxMint.d" -MT"src/TestLinuxMint.o" -o "src/TestLinuxMint.o" "../src/TestLinuxMint.cpp"
../src/TestLinuxMint.cpp: In instantiation of ‘static std::function<void()> ConcurrentTask<R(ArgTypes ...)>::bindTask(const std::function<_Res(_ArgTypes ...)>&, ArgTypes&& ...) [with R = int; ArgTypes = {int}]’:
../src/TestLinuxMint.cpp:58:84: required from ‘ConcurrentTask<R(ArgTypes ...)>::ConcurrentTask(int, const std::function<_Res(_ArgTypes ...)>&, ArgTypes&& ...) [with R = int; ArgTypes = {int}]’
../src/TestLinuxMint.cpp:91:53: required from here
../src/TestLinuxMint.cpp:76:90: error: conversion from ‘std::_Bind_helper<false, ConcurrentTask<R(ArgTypes ...)>::bindTask(const std::function<_Res(_ArgTypes ...)>&, ArgTypes&& ...) [with R = int; ArgTypes = {int}]::__lambda1&, int>::type {aka std::_Bind<ConcurrentTask<R(ArgTypes ...)>::bindTask(const std::function<_Res(_ArgTypes ...)>&, ArgTypes&& ...) [with R = int; ArgTypes = {int}]::__lambda1(int)>}’ to non-scalar type ‘std::function<void()>’ requested
std::function<void(void)> bound = std::bind(action, std::forward<ArgTypes>(args)...);
^
make: *** [src/TestLinuxMint.o] Error 1
16:31:01 Build Finished (took 319ms)
The issue seems to be on line 76, where there is a failed conversion from std::bind(*) to std::function<void(void)>. This code is definitely still under development, but I need to get past this issue to move forward. I've looked at multiple other posts here on SO, but all of them seem to be able to use std::bind on variadic template parameters without issue.
SOLUTION
Here is the final solution (as pertaining to this question) that I came up with thanks to kzraq and this post.
Source:
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <tuple>
#include <memory>
//------------------------------------------------------------------------------------------------------------
template <std::size_t... Ints>
struct idx_sequence
{
using type = idx_sequence;
using value_type = std::size_t;
static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
};
//------------------------------------------------------------------------------------------------------------
template <class Sequence1, class Sequence2>
struct _merge_and_renumber;
template <std::size_t... I1, std::size_t... I2>
struct _merge_and_renumber<idx_sequence<I1...>, idx_sequence<I2...> >
: idx_sequence<I1..., (sizeof...(I1)+I2)...>
{
};
//------------------------------------------------------------------------------------------------------------
template <std::size_t N>
struct make_idx_sequence : _merge_and_renumber<make_idx_sequence<N/2>, make_idx_sequence<N - N/2> >
{
};
template<> struct make_idx_sequence<0> : idx_sequence<> { };
template<> struct make_idx_sequence<1> : idx_sequence<0> { };
//------------------------------------------------------------------------------------------------------------
template<typename Func, typename Tuple, std::size_t... Ints>
auto applyImpl(Func&& f, Tuple&& params, idx_sequence<Ints...>)
-> decltype(f(std::get<Ints>(std::forward<Tuple>(params))...))
{
return f(std::get<Ints>(std::forward<Tuple>(params))...);
};
template<typename Func, typename Tuple>
auto apply(Func&& f, Tuple&& params)
-> decltype(applyImpl(std::forward<Func>(f),
std::forward<Tuple>(params),
make_idx_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}))
{
return applyImpl(std::forward<Func>(f),
std::forward<Tuple>(params),
make_idx_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{});
};
class ConcurrentTaskBase
{
public:
ConcurrentTaskBase(int priority, const std::function<void()>& task)
: m_thread(),
m_active(true)
{
auto wrap = [this](int priority, const std::function<void()>& task)
{
//Unrelated pthread stuff that I commented out
sched_param param{priority};
int err = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
if (err)
std::cout << "failed to set new priority: " << err << std::endl;
task();
};
m_thread = std::thread(wrap, priority, task);
}
virtual ~ConcurrentTaskBase(void)
{
waitForCompletion();
}
void waitForCompletion(void)
{
if (m_active)
{
m_thread.join();
m_active = false;
}
}
private:
std::thread m_thread;
bool m_active;
};
template<class R, class... ArgTypes>
class ConcurrentTask;
template<class R, class... ArgTypes>
class ConcurrentTask<R(ArgTypes...)> : public ConcurrentTaskBase
{
public:
ConcurrentTask(int priority, const std::function<R(ArgTypes...)>& task, ArgTypes&&... args)
: ConcurrentTaskBase(priority, bindTask(task, std::forward<ArgTypes>(args)...))
{}
std::shared_ptr<R> getReturn(void) noexcept
{
waitForCompletion();
return m_storage;
}
private:
std::function<void(void)> bindTask(const std::function<R(ArgTypes...)>& task, ArgTypes&&... args)
{
auto params = std::make_tuple(args...);
return [this, task, params](){m_storage = std::make_shared<R>(apply(task, params));};
};
std::shared_ptr<R> m_storage;
};
template<class... ArgTypes>
class ConcurrentTask<void(ArgTypes...)> : public ConcurrentTaskBase
{
public:
ConcurrentTask(int priority, const std::function<void(ArgTypes...)>& task, ArgTypes&&... args)
: ConcurrentTaskBase(priority, bindTask(task, std::forward<ArgTypes>(args)...))
{}
private:
std::function<void(void)> bindTask(const std::function<void(ArgTypes...)>& task, ArgTypes&&... args)
{
auto params = std::make_tuple(args...);
return [this, task, params](){apply(task, params);};
};
};
// Example stuff
struct MyStruct
{
int x;
int y;
};
int testFunction(MyStruct val)
{
std::cout << "X is " << val.x << " Y is " << val.y << std::endl;
return val.x + 10;
}
void printMe(int x)
{
std::cout << "Printing " << x << std::endl;
}
int main()
{
ConcurrentTask<int(MyStruct)> task(20, testFunction, {5, -21});
std::shared_ptr<int> received = task.getReturn();
std::cout << "Return value is " << *received << std::endl;
ConcurrentTask<void(int)> voidTask(25, printMe, -123);
return 0;
}
This is more or less what Yakk wrote about. Maybe I do not understand your idea well enough, but to me it seems that you've overengineered it and you're using std::function too early. Also, ArgTypes&& won't be a list of forwarding/universal references, since they're not deduced in bindTask.
The following compiles successfully on gcc 4.8.2:
Get your own integer_sequence for C++11. Courtesy of Xeo.
Write apply to apply tuple parameters to a function (maybe this could be improved):
template<typename Func, typename Tuple, unsigned int... is>
auto apply_impl(Func&& f, Tuple&& params, seq<is...>)
// -> decltype(f(std::get<is>(std::forward<Tuple>(params))...)) // C++11 only
{
using std::get; // enable ADL-lookup for get in C++14
return f(get<is>(std::forward<Tuple>(params))...);
}
template<typename Func, typename Tuple>
auto apply(Func&& f, Tuple&& params)
// -> decltype(apply_impl(std::forward<Func>(f), std::forward<Tuple>(params),
// GenSeq<std::tuple_size<typename std::decay<Tuple>::type>::value>{}))
// C++11 only
{
return apply_impl(std::forward<Func>(f), std::forward<Tuple>(params),
GenSeq<std::tuple_size<typename std::decay<Tuple>::type>::value>{});
}
Simplify your bindTask (though at this point I'd keep it as a template):
auto params = make_tuple(args...);
std::function<void(void)> bound = [task,params]{ apply(task, params); };
return bound;
In C++14 do [task=std::move(task),params=std::move(params)] to avoid needless copies.
As a guess, bind presumes it can be called repeatedly (esp when called in an lvalue context!), so does not turn rvalue parameters into rvalue parameters to its bound function as rvalue parameters. Which your code demands. That lambda is not perfect forwarding!
You are also capturing const& std::functions by reference in lambdas, which just invites dangling reference hell. But that is a runtime problem. As a general rule never & capture unless lifetime of lambda and all copies ends in the current scope; definitely don't do it during prototyping even if "certain" it won't be a problem.
I would consider writing a weak version of std::apply and index_sequences and packing the arguments into a tuple then doing your apply to unpack into the target callable. But that is a bias, dunno if ideal.
Related
I'm trying to store a member function of an unknown class with unkown arguments to be called later.
I found this code snippet to get the lambda:
template <auto Fn, typename T, typename R = void, typename... Args>
auto get_cb_inner(T* obj, R (T::*)(Args...) const) {
return [obj](Args... args) -> R {
return (obj->*Fn)(std::forward<Args>(args)...);
};
}
template <auto Fn, typename T>
auto get_cb(T* obj) {
return get_cb_inner<Fn, T>(obj, Fn);
}
But I can't figure out how I would store it and then be able to call it during runtime with the correct parameters.
I have a struct like this:
struct Job {
void execute(Data& data, const OtherData& otherData) const {
// do job
}
};
auto exe_fn = get_cb<&Job::execute>(new Job());
What I want to do is to store this "execute" function in a lambda and then store it in a vector-like container (with other functions that may have different arguments) that can be iterated and called on.
EDIT:
Using #KamilCuk code I created this wrapper-struct with no mem leaks/seg faults.
template <typename... Args>
using exec_fn = std::function<void(Args...)>;
template <typename Job>
using job_ptr = std::unique_ptr<Job>;
template <typename J, typename R = void, typename... Args>
struct JobExecuteCaller {
exec_fn<Args...> exec_fn;
job_ptr<J> job_ptr;
JobExecuteCaller (J* job, R (S::*f)(Args...) const)
: job_ptr{job_ptr<J>(job)} {
exec_fn = [this, f](Args... args) -> R {
(job_ptr.get()->*f)(std::forward<Args>(args)...);
};
}
void operator()(Args... args) { exec_fn(args...); }
};
auto process = JobExecuteCaller(new Job(), &Job::execute);
JobExecuteCaller(/*args ... */)
Now I just have to figure out a way to store different kinds of JobExecuteCallers.
You mean you want std::bind?
#include <utility>
#include <new>
#include <iostream>
#include <functional>
struct Job {
void execute(int a, int b) {
std::cout << a << " " << b << std::endl;
}
};
int main() {
auto exe_fn = std::bind(&Job::execute, new Job(),
std::placeholders::_1, std::placeholders::_2);
exe_fn(1, 2);
}
I have fixed your code. You need to pass not only the type of the function member pointer, but also the address of the function member pointer to the function. That way you can call it.
#include <utility>
#include <new>
#include <iostream>
#include <functional>
template <typename T, typename R = void, typename... Args>
auto get_cb(T* obj, R (T::*f)(Args...)) {
return [obj, f](Args... args) -> R {
return (obj->*f)(std::forward<Args>(args)...);
};
}
struct Job {
void execute(int a, int b) {
std::cout << a << " " << b << std::endl;
}
};
int main() {
auto exe_fn = get_cb(new Job(), &Job::execute);
exe_fn(1, 2);
}
Note that both examples leak memory from new Job().
I have a class that registers callback functions and calls them later that looks like this.
template<typename ReturnType, typename... Args>
class Signal {
std::vector<std::function<ReturnType(Args...)>> function;
public:
template<typename... Args2>
ReturnType operator()(Args2&&... args2) {
ReturnType ret;
for (auto& func : function)
ret = func(std::forward<Args2>(args2)...);
return ret;
}
template<typename Func>
void func(Func const &func) {
function.push_back(std::function<ReturnType(Args...)>(func));
}
template<typename Class, typename Instance>
void mfunc(ReturnType(Class::*func)(Args...), Instance &instance) {
mfunc2(func, instance, make_int_sequence<sizeof...(Args)>{});
}
template<typename Class, typename Instance, int... I>
void mfunc2(ReturnType(Class::*func)(Args...), Instance &instance, int_sequence<I...>) {
using namespace std::placeholders;
function.push_back(std::function<ReturnType(Args...)>(std::bind(func, &instance, placeholder_template<I>{}...)));
}
};
#include <iostream>
class foo {
public:
int bar(int x, double y) {
std::cout << x << " and " << y << std::endl;
return x*2;
}
};
int main() {
foo foo1;
Signal<int, int, double> sig;
sig.mfunc(&foo::bar, foo1);
std::cout << "Return: " << sig(5,5.5) << std::endl;
}
I heard a talk from Stephan T. Lavavej today, and one of the things he was saying is that std::bind should be avoided and use lambdas instead. So to learn something new I figured I would try and change the std::bind call in mfunc2 to a lambda, but I'm quite new to templates and can't figure out how to generate the code I want.
The current placeholder_template with make_int_sequence I found here on SO, but I can't really wrap my head around how exactly it works, or where to find any good reading on it...
Args... holds the argument types that should be accepted by the lambda, but I need to somehow create variable names such as var1, var2, var3 ect depending on the sizeof...(Args) and then merge them together.
So for example < int, int, int >, Args... would hold int, int.
I then want to construct the lambda as
[func, &instance](int var1, int var2) -> ReturnType { return func(&instance, var1, var2); }
How could I accomplish this?
This should do the job:
template<typename ReturnType, typename... Args>
class Signal {
std::vector<std::function<ReturnType(Args...)>> function;
public:
template<typename... Args2>
ReturnType operator()(Args2&&... args2) {
ReturnType ret;
for (auto& func : function)
ret = func(std::forward<Args2>(args2)...);
return ret;
}
template<typename Func>
void func(Func const &func) {
function.push_back(std::function<ReturnType(Args...)>(func));
}
template<typename Class, typename Instance>
void mfunc(ReturnType(Class::*func)(Args...), Instance& instance) {
function.push_back([&instance, func](Args&&... args) {
return (instance.*func)(std::forward<Args>(args)...);
});
}
};
https://ideone.com/gjPdWN
Note that in your operator(), you basically throw away all return values except the last one. Is that behaviour intended?
I currently have a system to "connect" signals to functions. This signal is a variadic template that has as template parameters the arguments of the functions it can connect to.
In the current implementation, I obviously cannot connect to functions whose arguments aren't exactly the same (or those that can be converted to) as the signal's parameters. Now, as I'm trying to mimic Qt's signal/slot/connect, I'd also like to connect a signal of N parameters to a slot of M<N parameters, which is perfectly well-defined (i.e. ignore the >M parameters of the signal and just pass the first M to the connected function). For an example of the code I have in its most simplistic form, see Coliru.
So the question is two-fold:
How do I make the connect call work for a function void g(int);?
How do I make the emit call work for a function void g(int);?
I'm guessing I'll have to make some "magic" parameter pack reducer for both the slot and its call function, but I can't see how it all should fit together so it's quite hard to actually start trying to code a solution. I'm OK with a C++17-only solution, if at least Clang/GCC and Visual Studio 2015 can compile it.
The code linked above for completeness:
#include <memory>
#include <vector>
template<typename... ArgTypes>
struct slot
{
virtual ~slot() = default;
virtual void call(ArgTypes...) const = 0;
};
template<typename Callable, typename... ArgTypes>
struct callable_slot : slot<ArgTypes...>
{
callable_slot(Callable callable) : callable(callable) {}
void call(ArgTypes... args) const override { callable(args...); }
Callable callable;
};
template<typename... ArgTypes>
struct signal
{
template<typename Callable>
void connect(Callable callable)
{
slots.emplace_back(std::make_unique<callable_slot<Callable, ArgTypes...>>(callable));
}
void emit(ArgTypes... args)
{
for(const auto& slot : slots)
{
slot->call(args...);
}
}
std::vector<std::unique_ptr<slot<ArgTypes...>>> slots;
};
void f(int, char) {}
int main()
{
signal<int, char> s;
s.connect(&f);
s.emit(42, 'c');
}
template<class...> struct voider { using type = void; };
template<class... Ts> using voidify = typename voider<Ts...>::type;
template<class C, class...Args>
using const_lvalue_call_t = decltype(std::declval<const C&>()(std::declval<Args>()...));
template<class T, std::size_t...Is>
auto pick_from_tuple_impl(T &&, std::index_sequence<Is...>)
-> std::tuple<std::tuple_element_t<Is, T>...>;
template<class Tuple, class = std::enable_if_t<(std::tuple_size<Tuple>::value > 0)>>
using drop_last = decltype(pick_from_tuple_impl(std::declval<Tuple>(),
std::make_index_sequence<std::tuple_size<Tuple>::value - 1>()));
template<class C, class ArgsTuple, class = void>
struct try_call
: try_call<C, drop_last<ArgsTuple>> {};
template<class C, class...Args>
struct try_call<C, std::tuple<Args...>, voidify<const_lvalue_call_t<C, Args...>>> {
template<class... Ts>
static void call(const C& c, Args&&... args, Ts&&... /* ignored */) {
c(std::forward<Args>(args)...);
}
};
Then in callable_slot:
void call(ArgTypes... args) const override {
using caller = try_call<Callable, std::tuple<ArgTypes...>>;
caller::call(callable, std::forward<ArgTypes>(args)...);
}
For member pointer support (this requires SFINAE-friendly std::result_of), change const_lvalue_call_t to
template<class C, class...Args>
using const_lvalue_call_t = std::result_of_t<const C&(Args&&...)>;
then change the actual call in try_call::call to
std::ref(c)(std::forward<Args>(args)...);
This is poor man's std::invoke for lvalue callables. If you have C++17, just use std::invoke directly (and use std::void_t instead of voidify, though I like the sound of the latter).
Not sure to understand what do you exactly want but... with std::tuple and std::make_index_sequence ...
First of all you need a type traits that give you the number of arguments of a function (or std::function)
template <typename>
struct numArgs;
template <typename R, typename ... Args>
struct numArgs<R(*)(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct numArgs<std::function<R(Args...)>>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
Next you have to add a constexpr value in callable_slot to memorize the number of arguments in the Callable function
static constexpr std::size_t numA { numArgs<Callable>::value };
Then you have to modify the call() method to pack the arguments in a std::tuple<ArgTypes...> and call another method passing the tuple and an index sequence from 0 to numA
void call(ArgTypes... args) const override
{ callI(std::make_tuple(args...), std::make_index_sequence<numA>{}); }
Last you have to call, in CallI(), the callable() function with only the first numA elements of the tuple of arguments
template <std::size_t ... Is>
void callI (std::tuple<ArgTypes...> const & t,
std::index_sequence<Is...> const &) const
{ callable(std::get<Is>(t)...); }
The following is a full working example
#include <memory>
#include <vector>
#include <iostream>
#include <functional>
template <typename>
struct numArgs;
template <typename R, typename ... Args>
struct numArgs<R(*)(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct numArgs<std::function<R(Args...)>>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename ... ArgTypes>
struct slot
{
virtual ~slot() = default;
virtual void call(ArgTypes...) const = 0;
};
template <typename Callable, typename ... ArgTypes>
struct callable_slot : slot<ArgTypes...>
{
static constexpr std::size_t numA { numArgs<Callable>::value };
callable_slot(Callable callable) : callable(callable)
{ }
template <std::size_t ... Is>
void callI (std::tuple<ArgTypes...> const & t,
std::index_sequence<Is...> const &) const
{ callable(std::get<Is>(t)...); }
void call(ArgTypes... args) const override
{ callI(std::make_tuple(args...), std::make_index_sequence<numA>{}); }
Callable callable;
};
template <typename ... ArgTypes>
struct signal
{
template <typename Callable>
void connect(Callable callable)
{
slots.emplace_back(
std::make_unique<callable_slot<Callable, ArgTypes...>>(callable));
}
void emit(ArgTypes... args)
{ for(const auto& slot : slots) slot->call(args...); }
std::vector<std::unique_ptr<slot<ArgTypes...>>> slots;
};
void f (int i, char c)
{ std::cout << "--- f(" << i << ", " << c << ")" << std::endl; }
void g (int i)
{ std::cout << "--- g(" << i << ")" << std::endl; }
struct foo
{
static void j (int i, char c)
{ std::cout << "--- j(" << i << ", " << c << ")" << std::endl; }
void k (int i)
{ std::cout << "--- k(" << i << ")" << std::endl; }
};
int main ()
{
std::function<void(int, char)> h { [](int i, char c)
{ std::cout << "--- h(" << i << ", " << c << ")" << std::endl; }
};
std::function<void(int)> i { [](int i)
{ std::cout << "--- i(" << i << ")" << std::endl; }
};
using std::placeholders::_1;
foo foo_obj{};
std::function<void(int)> k { std::bind(&foo::k, foo_obj, _1) };
signal<int, char> s;
s.connect(f);
s.connect(g);
s.connect(h);
s.connect(i);
s.connect(foo::j);
s.connect(k);
s.emit(42, 'c');
}
This example need C++14 because use std::make_index_sequence and std::index_sequence.
Substitute both of they and prepare a C++11 compliant solution isn't really difficult.
I'm trying to subclass std::thread such that a member function of the subclass is executed on the new thread before the caller's passed-in function. Something like the following invalid code:
#include <thread>
#include <utility>
class MyThread : public std::thread {
template<class Func, class... Args>
void start(Func&& func, Args&&... args) {
... // Useful, thread-specific action
func(args...);
}
public:
template<class Func, class... Args>
MyThread(Func&& func, Args&&... args)
: std::thread{[=]{start(std::forward<Func>(func),
std::forward<Args>(args)...);}} {
}
};
g++ -std=c++11 has the following issue with the above code:
MyThread.h: In lambda function:
MyThread.h:ii:jj: error: parameter packs not expanded with '...':
std::forward<Args>(args)...);}}
^
I've tried a dozen different variations in the initializer-list to no avail.
How can I do what I want?
The biggest difficulty I had when I did this before was getting all the behavior of std::thread. It's constructor can take not only a pointer to a free function, but also a class method pointer and then a object of the class as the first argument. There are a number of variations on that: class methods, class function object data members, an object of the class type vs a pointer to an object, etc.
This is for C++14:
class MyThread : public std::thread {
void prolog() const { std::cout << "prolog\n"; }
public:
template <typename... ArgTypes>
MyThread(ArgTypes&&... args) :
std::thread(
[this, bfunc = std::bind(std::forward<ArgTypes>(args)...)]
() mutable {
prolog();
bfunc();
})
{ }
};
If you put the prolog code inside the lambda and it doesn't call class methods, then the capture of this is not needed.
For C++11, a small change is needed because of the lack of capture initializers, so the bind must be passed as an argument to std::thread:
std::thread(
[this]
(decltype(std::bind(std::forward<ArgTypes>(args)...))&& bfunc) mutable {
prolog();
bfunc();
}, std::bind(std::forward<ArgTypes>(args)...))
Here's a test program that also exercises the class member form of std::thread:
int main()
{
auto x = MyThread([](){ std::cout << "lambda\n"; });
x.join();
struct mystruct {
void func() { std::cout << "mystruct::func\n"; }
} obj;
auto y = MyThread(&mystruct::func, &obj);
y.join();
return 0;
}
I haven't checked, but I'm a bit worried that the capture of this, also seen in other solutions, is not safe in some cases. Consider when the object is an rvalue that is moved, as in std::thread t = MyThread(args). I think the MyThread object will go away before the thread it has created is necessarily finished using it. The "thread" will be moved into a new object and still be running, but the captured this pointer will point to a now stale object.
I think you need to insure your constructor does not return until your new thread is finished using all references or pointers to the class or class members. Capture by value, when possible, would help. Or perhaps prolog() could be a static class method.
This should do it (c++11 and c++14 solutions provided):
C++14
#include <thread>
#include <utility>
#include <tuple>
class MyThread : public std::thread {
template<class Func, class ArgTuple, std::size_t...Is>
void start(Func&& func, ArgTuple&& args, std::index_sequence<Is...>) {
// Useful, thread-specific action
func(std::get<Is>(std::forward<ArgTuple>(args))...);
}
public:
template<class Func, class... Args>
MyThread(Func&& func, Args&&... args)
: std::thread
{
[this,
func = std::forward<Func>(func),
args = std::make_tuple(std::forward<Args>(args)...)] () mutable
{
using tuple_type = std::decay_t<decltype(args)>;
constexpr auto size = std::tuple_size<tuple_type>::value;
this->start(func, std::move(args), std::make_index_sequence<size>());
}
}
{
}
};
int main()
{
auto x = MyThread([]{});
}
In C++17 it's trivial:
#include <thread>
#include <utility>
#include <tuple>
#include <iostream>
class MyThread : public std::thread {
public:
template<class Func, class... Args>
MyThread(Func&& func, Args&&... args)
: std::thread
{
[this,
func = std::forward<Func>(func),
args = std::make_tuple(std::forward<Args>(args)...)] () mutable
{
std::cout << "execute prolog here" << std::endl;
std::apply(func, std::move(args));
std::cout << "execute epilogue here" << std::endl;
}
}
{
}
};
int main()
{
auto x = MyThread([](int i){
std::cout << i << std::endl;
}, 6);
x.join();
}
C++11 (we have to facilitate moving objects into the mutable lambda, and provide the missing std::index_sequence):
#include <thread>
#include <utility>
#include <tuple>
namespace notstd
{
using namespace std;
template<class T, T... Ints> struct integer_sequence
{};
template<class S> struct next_integer_sequence;
template<class T, T... Ints> struct next_integer_sequence<integer_sequence<T, Ints...>>
{
using type = integer_sequence<T, Ints..., sizeof...(Ints)>;
};
template<class T, T I, T N> struct make_int_seq_impl;
template<class T, T N>
using make_integer_sequence = typename make_int_seq_impl<T, 0, N>::type;
template<class T, T I, T N> struct make_int_seq_impl
{
using type = typename next_integer_sequence<
typename make_int_seq_impl<T, I+1, N>::type>::type;
};
template<class T, T N> struct make_int_seq_impl<T, N, N>
{
using type = integer_sequence<T>;
};
template<std::size_t... Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
}
template<class T>
struct mover
{
mover(T const& value) : value_(value) {}
mover(T&& value) : value_(std::move(value)) {}
mover(const mover& other) : value_(std::move(other.value_)) {}
T& get () & { return value_; }
T&& get () && { return std::move(value_); }
mutable T value_;
};
class MyThread : public std::thread {
template<class Func, class ArgTuple, std::size_t...Is>
void start(Func&& func, ArgTuple&& args, notstd::index_sequence<Is...>) {
// Useful, thread-specific action
func(std::get<Is>(std::forward<ArgTuple>(args))...);
}
public:
template<class Func, class... Args>
MyThread(Func&& func, Args&&... args)
: std::thread()
{
using func_type = typename std::decay<decltype(func)>::type;
auto mfunc = mover<func_type>(std::forward<Func>(func));
using arg_type = decltype(std::make_tuple(std::forward<Args>(args)...));
auto margs = mover<arg_type>(std::make_tuple(std::forward<Args>(args)...));
static_cast<std::thread&>(*this) = std::thread([this, mfunc, margs]() mutable
{
using tuple_type = typename std::remove_reference<decltype(margs.get())>::type;
constexpr auto size = std::tuple_size<tuple_type>::value;
this->start(mfunc.get(), std::move(margs).get(), notstd::make_index_sequence<size>());
});
}
};
int main()
{
auto x = MyThread([](int i){}, 6);
x.join();
}
I tried to build a function template that can measure the execution time of functions of arbitrary type. Here is what I've tried so far:
#include <chrono>
#include <iostream>
#include <type_traits>
#include <utility>
// Executes fn with arguments args and returns the time needed
// and the result of f if it is not void
template <class Fn, class... Args>
auto timer(Fn fn, Args... args)
-> std::pair<double, decltype(fn(args...))> {
static_assert(!std::is_void<decltype(fn(args...))>::value,
"Call timer_void if return type is void!");
auto start = std::chrono::high_resolution_clock::now();
auto ret = fn(args...);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
return { elapsed_seconds.count(), ret };
}
// If fn returns void, only the time is returned
template <class Fn, class... Args>
double timer_void(Fn fn, Args... args) {
static_assert(std::is_void<decltype(fn(args...))>::value,
"Call timer for non void return type");
auto start = std::chrono::high_resolution_clock::now();
fn(args...);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
return elapsed_seconds.count();
}
int main () {
//This call is ambigous if the templates have the same name
std::cout << timer([](double a, double b){return a*b;},1,2).first;
}
Notice that I have to have a function with a different name for void(...) functions. Is there any way to get rid of the second function?
(And is what I did correct in the first place?)
You can use enable_if or tag dispatching. Enable_if seems to be the quicker way in this case:
#include <type_traits>
template <class Fn, class... Args>
auto timer(Fn fn, Args && ... args) -> typename std::enable_if<
// First template argument is the enable condition
!std::is_same<
decltype( fn( std::forward<Args>(args) ... )),
void >::value,
// Second argument is the actual return type
std::pair<double, decltype(fn(std::forward<Args>(args)...))> >::type
{
// Implementation for the non-void case
}
template <class Fn, class... Args>
auto timer(Fn fn, Args &&... args) -> typename std::enable_if<
std::is_same<
decltype( fn( std::forward<Args>(args) ... )),
void >::value,
double>::type
{
// Implementation for void case
}
Also you should use perfect forwarding to pass the arguments to the called function:
auto timer(Fn fn, Args && ... args) // ...
~~~^
And when you call the function:
auto ret = fn( std::forward<Args>(args)...);
Demo. Notice that this works with functions, lambda and callable objects; pretty much everything with an operator().
From a design standpoint, I see no problem in returning a std::pair. Since C++11 has std::tie, returning a pair/ tuple is the legitimate way of returning multiple results from a function. I would go forward and say that for consistency in the void case you should return a tuple with only one element.
In this case I would pass the duration as a reference to the the wrapper of the function call:
#include <chrono>
#include <iostream>
#include <thread>
template <typename Duration, class Fn, class... Args>
auto call(Duration& duration, Fn fn, Args... args) -> decltype(fn(args...)) {
using namespace std::chrono;
struct DurationGuard {
Duration& duration;
high_resolution_clock::time_point start;
DurationGuard(Duration& duration)
: duration(duration),
start(high_resolution_clock::now())
{}
~DurationGuard() {
high_resolution_clock::time_point end = high_resolution_clock::now();
duration = duration_cast<Duration>(end - start);
}
};
DurationGuard guard(duration);
return fn(args...);
}
void f() {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int g() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 42;
}
int main () {
using namespace std::chrono;
duration<double> s;
call(s, f);
std::cout << s.count() << '\n';
milliseconds ms;
int n = call(ms, g);
std::cout << ms.count() << ", " << n << '\n';
}
You may wrap it up in a class:
#include <chrono>
#include <iostream>
#include <thread>
template <typename Duration = std::chrono::duration<double>>
class InvokeDuration
{
public:
template<typename Fn, class... Args>
auto operator () (Fn fn, Args... args) -> decltype(fn(args...)) {
using namespace std::chrono;
struct Guard {
Duration& duration;
high_resolution_clock::time_point start;
Guard(Duration& duration)
: duration(duration),
start(high_resolution_clock::now())
{}
~Guard() {
high_resolution_clock::time_point end = high_resolution_clock::now();
duration = duration_cast<Duration>(end - start);
}
};
Guard guard(m_duration);
return fn(args...);
}
const Duration& duration() const { return m_duration; }
typename Duration::rep count() const { return m_duration.count(); }
private:
Duration m_duration;
};
void f() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
int g(int n) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return n;
}
int main () {
InvokeDuration<> invoke;
invoke(f);
std::cout << invoke.count() << '\n';
int n = invoke(g, 42);
std::cout << invoke.count() << ", " << n << '\n';
}
Note: Returning void from a function call is well defined: void a() { return b(); } with void b()
Just overload it. Also, you should change the function signature as below. Live code.
template <typename R, typename... Args>
auto timer(R (*fn)(Args...), Args... args) -> std::pair<double, R>
{
//...
auto ret = fn(args...);
//...
return { elapsed_seconds.count(), ret };
}
And for void:
template <typename... Args>
auto timer(void (*fn)(Args...), Args... args) -> double
{
//...
fn(args...);
//...
return elapsed_seconds.count();
}
However it doesn't work for lambdas.
There is a workaround for non-capturing lambda functions (which brakes the generalization).
template <typename Function>
struct function_traits
: public function_traits<decltype(&Function::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
typedef ReturnType (*pointer)(Args...);
typedef std::function<ReturnType(Args...)> function;
};
template <typename Function>
typename function_traits<Function>::pointer
to_function_pointer (const Function& lambda)
{
return static_cast<typename function_traits<Function>::pointer>(lambda);
}
and then you can pass lambdas like this:
timer(to_function_pointer([](){
// Lambda function
}));
C++14 generic lambdas remove the need to use templates. A code snippet I saw in Effective Modern C++ demonstrates this :
auto timeFuncInvocation =
[](auto&& func, auto&&... params)
{
start timer;
std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...);
stop timer and record elapsed time;
};