I'm writing some multithreaded code and using promise/future to call a function on a different thread and return its result. For simplicitly, I'll remove the threading part entirely:
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::promise<decltype(f())> promise;
// fulfill the promise
promise.set_value(f());
// block until we have a result
return promise.get_future().get();
}
This works great for any function that returns non-void. And the return statement getting the future also works for void. But I can't fulfill the promise if f is a void function, because:
promise.set_value(f()); // error: invalid use of void expression
Is there some clever way of setting the value in the void case in-line, or do I have to just write a helper function like call_set_value(promise, f) that has an overloads for std::promise<R> and std::promise<void>?
A promise is only one kind of asynchronous result provider. Instead of a promise you could use a packaged_task which wraps a callable object, similar to a std::function except that invoking it makes the result available via a future (and of course it handles the difference between void and non-void results):
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::packaged_task<decltype(f())()> task(std::move(f));
task();
// block until we have a result
return task.get_future().get();
}
N.B. according to the current standard, this code would have a data race if task() and task.get_future() happen on separate threads (and so would your original using a promise), so you should call get_future() before handing the task to the other thread. In practice it should be safe on real implementations and there's a library issue (LWG 2412) to make it valid anyway.
Yes. Function overload is the cleanest solution:
set(promise, f);
then implement set as overloaded functions, as:
template<typename F, typename R>
void set(std::promise<R> & p, F && f) //handle non-void here
{
p.set_value(f());
}
template<typename F>
void set(std::promise<void> & p, F && f) //handle void here
{
f();
p.set_value();
}
Related
I am trying to store lambda functions in a queue to execute them later. In order to do that, i am trying to hide the parameter pack in a lambda without losing scope so I can still access the passed arguments in an upper scope.
Sadly I cannot compile this since the parameter pack does not match the const qualifier.
I hope it is easier to understand what I am trying to accomplish by looking at the following code. (I am using c++17, not c++20).
I think I misunderstand how to properly forward the variadic parameter pack since as I do it right now, the binding reference to const will discard qualifiers.
It is sadly not an option to expect the parameters in the functional lambda to be const.
std::queue<std::function<void()>> fcts;
template<typename F >
auto push_fct(F &task) -> void {
// Do things
fcts.push(std::move(std::function<void()>(task)));
}
template<typename F, typename... A>
auto push_fct(F& task , A&... args) -> void {
push_fct( [task, args...] { task(args...);});
}
auto main() -> int {
auto functional = [&](class_a & a, class_b & b) {
a.memberFct();
b.memberFunction(123);
}
class_a instance_a;
class_b instance_b;
push_fct(functional, instance_a, instance_b);
return 0;
}
What happens is, here [task, args...] the references are lost; task, args... are captured by value, which, in a non-mutable lambda additionally become const, which subsequently can't bind to non-const references in the call to [&](class_a & a, class_b & b).
You can capture the references by reference. Don't worry about their lifetime - the references are collapsed, and the original ones will be captured (source).
template<typename F>
auto push_fct(F&& task) -> void {
// Do things
fcts.emplace(std::forward<F>(task));
}
template<typename F, typename... A>
auto push_fct(F& task, A&... args) -> void {
push_fct([&task, &args...]{ task(args...); });
}
I've been looking into writing a static_if for my C++ project, and I stumbled across the following piece of code:
#include <iostream>
using namespace std;
namespace static_if_detail {
struct identity {
template<typename T>
T operator()(T&& x) const {
return std::forward<T>(x);
}
};
template<bool Cond>
struct statement {
template<typename F>
void then(const F& f){
f(identity());
}
template<typename F>
void else_(const F&){}
};
template<>
struct statement<false> {
template<typename F>
void then(const F&){}
template<typename F>
void else_(const F& f){
f(identity());
}
};
} //end of namespace static_if_detail
template<bool Cond, typename F>
static_if_detail::statement<Cond> static_if(F const& f){
static_if_detail::statement<Cond> if_;
if_.then(f);
return if_;
}
template<typename T>
void decrement_kindof(T& value){
static_if<std::is_same<std::string, T>::value>([&](auto f){
f(value).pop_back();
}).else_([&](auto f){
--f(value);
});
}
int main() {
// your code goes here
std::string myString{"Hello world"};
decrement_kindof(myString);
std::cout << myString << std::endl;
return 0;
}
It all makes sense to me, except for one thing: the overloaded operator() in struct identity. It takes in a rhs of type T called x, cool and all. But when identity is called, nothing is actually passed into identity.
template<typename F>
void then(const F& f){
f(identity());
}
Above, f calls identity, but passes nothing onto identity. Yet identity returns the forwarded arguments (in my case, an std::string), and pops the backmost character of the string.
How is identity returning a forwarded argument, when itself has no arguments passed into it to forward?
f doesn't call identity - f is called with an instance of identity. Walking through the two cases here:
static_if<std::is_same<std::string, T>::value>([&](auto f){
f(value).pop_back();
}).else_([&](auto f){
--f(value);
});
If T is std::string, then we instantiate a statement<true> whose then() invokes the passed-in function with an instance of identity. The argument to the first lambda, f, will be of type identity - so f(value) is really just value and we do value.pop_back().
If T is not std::string, then we instantiate a statement<false> whose then() does nothing, and whose else_() invokes the lambda with an instance of identity. Again f(value) is just value and we do --value.
This is a really confusing implementation of static_if, since f in the lambda is always an identity. It's necessary to do because we can't use value directly (can't write value.pop_back() since there's no dependent name there so the compiler will happily determine that it's ill-formed for integers), so we're just wrapping all uses of value in a dependent function object to delay that instantiation (f(value) is dependent on f, so can't be instantiated until f is provided - which won't happen if the function isn't called).
It would be better to implement it so that you actually pass in the arguments to the lambda.
template<typename F>
void then(const F& f){
f(identity());
}
Is more readable as
template<typename F>
void then(const F& f){
f(identity{});
}
they are construcing an identity object, not calling one.
The trick here is that the non-dependent parts of a template function must be valid even if the function is never instantiated.
So saying value.pop_back() is never valid within the lambda when value is an integer.
By passing identity{} to exactly one of the then or else cases, we can avoid this problem.
The statement f(value) produces a dependent type. So it need only be valid when the template operator() of the lambda is actually instantiated (there must also be some possibke f that makes it valid, but that is a corner case).
As we only instantiate the path the condition tells us to, the f(value) can be used almost any way we want, so long as it is valid in the taken branch.
I would have called f a better name, like safe or guard or var or magic rather than f. The use of two fs different contexts in the terse code adds to the confusion.
Let us take the case, where your Cond is true in the static_if, hence, the primary template class will be used...
template<bool Cond>
struct statement {
template<typename F>
void then(const F& f){
f(identity());
}
template<typename F>
void else_(const F&){}
};
Recall, that your calling function is:
static_if<std::is_same<std::string, T>::value>
(
[&](auto f){ //This is the lamda passed, it's a generic lambda
f(value).pop_back();
}
).else_(
[&](auto f){
--f(value);
}
);
In the applying function below, F is a type of that generic lambda (meaning, you can call f with any type)
template<typename F>
void then(const F& f){
f(identity());
}
identity() creates an object of type identity which is then passed as an argument, to call your generic lambda.
[&](auto f){ //This is the lamda passed, it's a generic lambda
f(value).pop_back();
}
but recall, f is an object of type identity and has a templated call () operator, which basically returns the object passed to it.
So, we go like this:
void decrement_kindof(std::string& value){
static_if<std::is_same<std::string, std::string>::value>([&](auto f){
f(value).pop_back();
}).else_([&](auto f){
--f(value);
});
});
Reduced to:
void decrement_kindof(std::string& value){
static_if<true>([&](auto f){
f(value).pop_back();
}).else_([&](auto f){
--f(value);
});
});
Reduced to:
void decrement_kindof(std::string& value){
static_if<true>(
[&](identity ident){
auto&& x = ident(value); //x is std::string()
x.pop_back();
} (identity()) //<-- the lambda is called
).else_(
[&](auto f){ //This is not evaluated, because it's not called by the primary template of `statement`
--f(value);
}
);
});
What I want to do is design a class that can execute a function asynchronously. I need warp it in member function, because I want to know whether it complete or not.
The basic design is the following:
struct SelectionAsynMission
{
template<typename Function, typename...Args>
void start(Function && f, Args&&...a)
{
// compiler failed here
thread_.swap(thread(std::bind(&SelectionAsynMission::execute_warp<Function, Args ...>, this), f,std::forward<Args>(a)...));
//thread_.swap(std::thread(f, std::forward<Args>(a)...)); no warp work fine
thread_.detach();
}
template<typename Function, typename...Args>
void execute_warp(Function && f, Args&& ... a)
{
thread_complete_ = false;
f(std::forward<Args>(a)...);
thread_complete_ = true;
}
void join();
atomic<bool> thread_complete_; // Use atomic to tell the main thread whether it is complete.
thread thread_;
};
The Compile Error is:
error C2064: term does not evaluate to a function taking 1 arguments
So any suggestion for the design to fulfill the requirement
Or ideas about fix the compile error would be helpful.
Thank you for your help, I was stupid enough to forget the basic of std::bind.
Before see your comments and answers
I have tried another way to do this. I use async to warp the function, and instead the atomic, i use future status to determine whether the job complete. I wasn't sure which cost more time, read atomic or future status, but the future status seems easier.
template<class Function, class...Args>
void start(Function && f, Args&... a)
{
// start the function with async
future_node_ = std::async(std::launch::async,f,std::forward<Args&>(a)...);
}
bool iscomplete()
{
// wait for zero time to get status.
auto status = future_node_.wait_for(std::chrono::nanoseconds(0));
// determine whether the job is done
return status == std::future_status::ready;
}
Well, you have kind of a skeleton of something usable. But the error is pretty obvious if you look where the error is coming from:
std::thread(std::bind(member_fn, this), fn, args...)
You're trying to pass arguments to a function object returned from a std::bind that doesn't take any arguments.
What you want to do is pretty hard using std::bind, because it requires the std::placeholders constructs _1, _2, _3, etc, etc to signal that there are _n many args to be passed. That would require some template trickery.
A better option would be to use a lambda expression; a feature of C++11, which you are probably using seeing as though you make use of std::thread which is another C++11 feature.
Here's how to do it using lambdas:
class myclass{
template<typename Func, typename ... Args>
void start(Func &&f, Args &&... args){
m_thread.swap(std::thread{
[this](Func &&f, Args &&... uargs){
this->execute_warp(std::forward<Func>(f), std::forward<Args>(uargs)...);
},
std::forward<Func>(f), std::forward<Args>(args)...
});
m_thread.detach();
}
template<typename Func, typename ... Args>
void execute_warp(Func &&f, Args &&... args){
m_thread_done = false;
f(std::forward<Args>(args)...);
m_thread_done = true;
}
void join(){
while(!m_thread_done.load(std::memory_order_relaxed)){}
}
std::atomic<bool> m_thread_done;
std::thread m_thread;
}
And I might add a way to do it using std::bind to my answer.
Can generic lambdas take advantage of the "Substitution Failure Is Not An Error" rule ? Example
auto gL =
[](auto&& func, auto&& param1, auto&&... params)
-> enable_if_t< is_integral<
std::decay_t<decltype(param1)>
>::value>
{
// ...
};
auto gL =
[](auto&& func, auto&& param1, auto&&... params)
-> enable_if_t< !is_integral<
std::decay_t<decltype(param1)>
>::value>
{
// ...
};
Are there any workarounds or plans to include this in the language ? Also since generic lambdas are templated function objects under the hood isn't it a bit odd that this can't be done ?
Lambdas are function objects under the hood. Generic lambdas are function objects with template operator()s.
template<class...Fs>
struct funcs_t{};
template<class F0, class...Fs>
struct funcs_t<F0, Fs...>: F0, funcs_t<Fs...> {
funcs_t(F0 f0, Fs... fs):
F0(std::move(f0)),
funcs_t<Fs...>(std::move(fs)...)
{}
using F0::operator();
using funcs_t<Fs...>::operator();
};
template<class F>
struct funcs_t<F>:F {
funcs_t(F f):F(std::move(f)){};
using F::operator();
};
template<class...Fs>
funcs_t< std::decay_t<Fs>... > funcs(Fs&&...fs) {
return {std::forward<Fs>(fs)...};
}
auto f_all = funcs( f1, f2 ) generates an object that is an overload of both f1 and f2.
auto g_integral =
[](auto&& func, auto&& param1, auto&&... params)
-> std::enable_if_t< std::is_integral<
std::decay_t<decltype(param1)>
>{}>
{
// ...
};
auto g_not_integral =
[](auto&& func, auto&& param1, auto&&... params)
-> std::enable_if_t< !std::is_integral<
std::decay_t<decltype(param1)>
>{}>
{
// ...
};
auto gL = funcs( g_not_integral, g_integral );
and calling gL will do SFINAE friendly overload resolution on the two lambdas.
The above does some spurious moves, which could be avoided, in the linear inheritance of funcs_t. In an industrial quality library, I might make the inheritance binary rather than linear (to limit instantiation depth of templates, and the depth of the inheritance tree).
As an aside, there are 4 reasons I know of to SFINAE enable lambdas.
First, with new std::function, you can overload a function on multiple different callback signatures.
Second, the above trick.
Third, currying a function object where it evaluates when it has the right number and type of args.
Forth, automatic tuple unpacking and similar. If I'm using continuation passing style, I can ask the passed in continuation if it will accept the tuple unpacked, or the future unbundled, etc.
A generic lambda can only have one body, so SFINAE wouldn't be of much use here.
One solution would be to package the call into a class which can store the result and is specialized on a void return type, encapsulating the void special handling away from your lambda. With a very little overhead, you can do this using the thread library facilities:
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
std::packaged_task<Ret()> task{[&]{
return std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...); }};
auto fut = task.get_future();
task();
// stop timer and print elapsed time
return fut.get();
};
If you want to avoid the overhead of packaged_task and future, it's easy to write your own version:
template<class T>
struct Result
{
template<class F, class... A> Result(F&& f, A&&... args)
: t{std::forward<F>(f)(std::forward<A>(args)...)} {}
T t;
T&& get() { return std::move(t); }
};
template<>
struct Result<void>
{
template<class F, class... A> Result(F&& f, A&&... args)
{ std::forward<F>(f)(std::forward<A>(args)...); }
void get() {}
};
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
Result<Ret> k{std::forward<decltype(func)>(func),
std::forward<decltype(params)>(params)...};
// stop timer and print elapsed time
return k.get();
};
The use of SFINAE is to remove an overload or a specialization from the candidate set when resolving a given function or template. In your case, we have a lambda - that is a functor with a single operator(). There is no overload, so there is no reason to use SFINAE1. The fact that the lambda is generic, which makes its operator() a function template, doesn't change that fact.
However, you don't actually need to differentiate between different return types. If func returns void for the given arguments, you can still return it. You just can't assign it to a temporary. But you don't have to do that either:
auto time_func = [](auto&& func, auto&&... params) {
RaiiTimer t;
return std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...);
};
Just write an RaiiTimer whose constructor starts a timer and whose destructor stops it and prints the result. This will work regardless of func's return type.
If you need something more complicated than that, then this is one of those cases where you should prefer a functor over a lambda.
1Actually, as Yakk points out, SFINAE could still be quite handy to check if your function is callable period, which isn't the problem you're trying to solve - so in this case, still not very helpful.
If I have a function which is required to produce a hook from an input object, should I try to do that without casting to std::function? With these 2 options, which should I pick and is option 2 a meaningful improvement?
std::function<void()> CreateHook(std::function<void()> f)
{
return []()
{
return Hook(f);
};
}
// option 1:
void Hook(std::function<void()> f)
{
// do something
}
// option 2:
<typename F>
void Hook(F f)
{
// do something
}
Type erase only when you need to. Either:
template<class F>
std::function<void()> CreateHook(F f) { return []() { return Hook(f); }; }
or even in C++1y:
template<class F>
auto CreateHook(F f) { return [f=std::move(f)]() { return Hook(f); }; }
but the second is probably overkill (the f=std::move(f) is not, but auto is, as I am guessing you will just store the return value in a std::function anyhow).
And if your Hook function is simple and stable:
template <typename F> void Hook(F f) {
// do something
}
but if it is large and complex:
void Hook(std::function<void()> f) {
// do something
}
because it lets you split interface from implementation.
The downside to this strategy is that some compilers suck at eliminating identical code in different functions causing binary size bloat, and it can cause some compile time bloat.
But if you defer type erasure in both cases, you can eliminate both two virtual function calls, and allow the compiler to inline the passed in f within the Hook body.
If however the interface for CreateHook cannot be changed, and Hook is only called from it, the template version of Hook is pointless, as it is only called with a std::function anyhow.
In your example the template is pointless, because it is only ever instantiated for T = std::function<void()> - the template overload is chosen by static type of f, not the runtime type.