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...); });
}
Related
When passing the arguments to std::bind they are always copied or moved, unless wrapped by std::ref and I want to do the same with a lambda expression.
The Problem is, that I want to wrap the generation of the lambda expression in a function and forward the arguments as passed by the user to the lambda. The reason I want to do this, is that I want to call the lambda asynchronously and let the user decide if the arguments shall be passed by reference or by copy.
Consider the following example. I have the function print_address that takes the parameter as reference. Then I have the function combine_and_call_bind that forwards the arguments into std::bind.
void print_address(int& a) {
std::cout << "Adress of a = " << &a << std::endl;
}
template<typename F, typename Args>
void combine_and_call_bind(F f, Args&& args) {
auto a = std::bind(f, std::forward<Args>(args));
a();
}
The user can the specify when calling the combine_and_call_bind-function if the arguments shall be copied into std::bind or if they shall be passed by reference by wrapping the arguments in std::ref:
combine_and_call_bind(print_address, a); // copy a into std::bind
combine_and_call_bind(print_address, std::ref(a)); // pass a as reference into std::bind
How can I do the same with the following function combine_and_call_lambda, while using C++11?
template<typename F, typename Args>
void combine_and_call_lambda(F f, Args&& args) {
auto a = [/* std::forward<Args>(args) */, f] {
f(args);
};
a();
}
You might try to capture everything by value:
template<typename F, typename... Args>
void combine_and_call_lambda(F f, Args&&... args) {
auto a = [=]() mutable {
f(args...);
};
a();
}
Then use:
combine_and_call_lambda(print_address, a);
combine_and_call_lambda(print_address, std::ref(a));
DEMO
As we can see at lambda:
captures - a comma-separated list of zero or more captures, optionally
beginning with a capture-default.
Capture list can be passed as follows (see below for the detailed
description):
...
[=] captures all automatic variables used in the body of the lambda
by copy and current object by reference if exists
So, in the code above everything is copied and stored inside the lambda object.
Let's say a I have a typedef for a specific std::function such as:
typedef std::function<int(int a, int b, int c)> func_type;
Can I reuse that typedef when defining a lambda that implements it?
For example, in the example below, the function foo accepts a func_type, but the call-site for foo needs to replicate the signature:
void foo(func_type f) {
// ...
}
int main() {
foo([](int a, int b, int c){ return a + b + c; });
}
Can I somehow re-use the func_type typedef when declaring the lambda, so I don't have to repeat the argument list (and so changes to the func_type typedef will be transparent for lambda bodies that work with the new definition).
Something like [](??? func_type ???){ return a + b + c; }.
The variable names in std::function<int(int a, int b, int c)> are not part of the type -- they are basically comments. There is no way to extract them at any other point.
So if you hope to get a, b and c you are out of luck.
One simple thing you can do is use auto:
foo( [](auto...args) { return args+...+0; } );
which is close to what you want. If you have 3 arguments you can do:
foo( [](auto a, auto b, auto c) { return a+b+c; } );
But the return type doesn't match, other than because std::function does the conversion for you.
You can extract the types of a b and c and make the lambda work differently, but not with the return type. Not unless you do something insane like:
template<class T>
struct tag_t{ contexpr tag_t(){} using type=T; };
template<class T>
constexprt tag_t<T> tag{};
template<class Tag>
using type_t = typename Tag::type;
template<class F>
struct deducer {
F f;
template<class R, class...Args>
operator std::function<R(Args...)>() const {
return f( tag<R>, tag<Args>... );
}
};
template<class F>
deducer<F> make_deducer( F f ){ return {std::move(f)}; }
int main() {
foo(make_deducer([](auto R, auto...Args){
return []( type_t<decltype(Args)>... args )->type_t<decltype(R)> {
return 0+...args;
});
}));
}
I would advise against this. But I deduced the argument types and return type of the lambda from what std::function I was passed to.
What we do here is we create a deducer type, that when converted to a std::function passes the arguments and return type expected to a lambda it stores. That lambda then generates a custom lambda for those exact arguments.
This is neither brief, simple nor sane.
If you know you have a std::function and what you want to do is defer the selection of the type arguments to std::function, you can just have a generic lambda:
foo([](auto... xs) { return (... + xs); });
Since it's std::function's call operator that drives how the lambda is called, this'll do the right thing. Of course, this requires C++14 (and the fold-expression I used above requires C++17, but that's not as important). You may or may not want to use auto&&, depending on what the types actually are.
For C++11, you can't easily do such a thing with a lambda. You'd need to fix the arity and manually list all the types. This isn't practical. You could fallback to using a normal function object, with a call operator template, but then you lose the advantages of a lambda.
A std::function is
is a general-purpose polymorphic function wrapper. Instances of
std::function can store, copy, and invoke any Callable target --
functions, lambda expressions, bind expressions, or other function
objects, as well as pointers to member functions and pointers to data
members. -- source cppreference.com
So yes, this approach is perfectly valid !
However the signature of the typedef can't be taken over to short-circuit the lambda definition.
Remark: The typedef is about the return type and the parameter types but not the parameter names, so if short-circuiting the parameter list would be legal, the body of the lambda would not know which parameters to use:
int main() {
foo([](int d, int e, int f){ return d + e + f; });
}
I have the following api:
old_operation(stream, format, varArgs);
And I want to write an adaptor to make it possible to write the call as follows:
stream << operation(format, varArgs);
To do this I'm using a temporary object which stores references to varArgs and overload the operator<< to apply the old_operation() as follows:
template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
template<typename ...T>
class Operation
{
using Storage = decltype(storage(std::declval<T>()...));
public:
template<typename ...Args>
explicit Operation(Args&& ...args) :
mArgs(storage(std::forward<Args>(args)...)) {};
template<class StreamType>
StreamType& Apply(StreamType& stream)
{
auto f = [&](auto&& ...xs)
{
old_operation(stream, std::forward<decltype(xs)>(xs)...);
}
mArgs(f);
return stream;
}
private:
Storage mArgs;
};
template<typename ...Args>
Operation<Args...> MakeOperation(Args&&... args)
{
return Operation<Args...>(std::forward<Args>(args)...);
}
template<class StreamType, typename ...Args>
StreamType& operator<<(StreamType& stream, Operation<Args...>&& operation)
{
return operation.Apply(stream);
}
This works great but now I need to add some using namespace declarations embedded into the operation call:
let's say I have
namespace X {namespace Y { namespace Z { int formater(double x) { return std::round(x); }}}
And I don't want to add all the namespaces for this call, so I'm doing something like:
#define OPERATION(...) \
[&]() { \
using namespace ::X:Y:Z; \
return Operation("" __VA_ARGS__); }() \
which allows me to do:
stream << OPERATION(format, formater(2.3));
The problem with the lambda is that the temporaries are being created in a different scope than the Apply() call, which is UB.
I don't know if by adding a const qualifier to mArgs it will prolong the life of the captured references as mentioned here. I'm not sure if this applies, I'm assuming they are stack-based references and that by adding the const qualifier to mArgs the qualifier is going to be applied to the captured references.
template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
this is a haskell-style functor (well, a variardic one, which isn't very haskell). It takes Ts... and returns a function of type ((Ts...)->U)->U, ie that knows how to evaluate a function on the arguments you passed to it. This makes storage of type (Ts...)->( ((Ts...)->U)->U ) for a bit of algebraic fun.
I suspect your problem is that you have temporaries that you don't store. Generally not storing temporaries passed to a function, where the return value depends on the lifetime of those temporaries, results in fragile code.
If you have C++1z experimental::apply we can do this:
template<class... Ts>
decltype(auto) storage(Ts&&... ts) {
return
[tup=std::tuple<Ts...>(std::forward<Ts>(ts)...)]
(auto&& f)
->decltype(auto) mutable
{
return std::experimental::apply(decltype(f)(f), std::move(tup));
};
}
which returns a one-shot delayed call to std::apply. Apply takes a function and a tuple, and passes the arguments of the tuple to the function. It handles reference and r/lvalue-ness properly. Meanwhile, the container of the tuple makes the capture simpler, and lets us easily conditionally store rvalues while keeping lvalues as references.
I think this solves your problem, as temporaries get moved-into the tuple instead of being captured by reference, while non-temporaries are stored by reference.
There should be std::experimental::apply implementations that are better than anything I can sketch here available easily.
This seems like something that ought to be frequently asked and answered, but my search-fu has failed me.
I'm writing a function which I want to accept a generic callable object of some kind (including bare function, hand-rolled functor object, bind, or std::function) and then invoke it within the depths of an algorithm (ie. a lambda).
The function is currently declared like this:
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
I'm accepting the functor by reference because I want to guarantee that it does not get copied on entry to the function, and thus the same instance of the object is actually called. And it's a const reference because this is the only way to accept temporary objects (which are common when using hand-rolled functors or bind).
But this requires that the functor implement operator() as const. I don't want to require that; I want it to be able to accept both.
I know I can declare two copies of this method, one that accepts it as const and one as non-const, in order to cover both cases. But I don't want to do that as the comments are hiding quite a lot of code that I don't want to duplicate (including some loop constructs, so I can't extract them to a secondary method without just moving the problem).
I also know I could probably cheat and const_cast the functor to non-const before I invoke it, but this feels potentially dangerous (and in particular would invoke the wrong method if the functor intentionally implements both const and non-const call operators).
I've considered accepting the functor as a std::function/boost::function, but this feels like a heavy solution to what ought to be a simple problem. (Especially in the case where the functor is supposed to do nothing.)
Is there a "right" way to satisfy these requirements short of duplicating the algorithm?
[Note: I would prefer a solution that does not require C++11, although I am interested in C++11 answers too, as I'm using similar constructs in projects for both languages.]
Have you tried a forwarding layer, to force inference of the qualifier? Let the compiler do the algorithm duplication, through the normal template instantiation mechanism.
template<typename T, typename F>
size_t do_something_impl(const T& a, F& f)
{
T internal_value(a);
const T& c_iv = interval_value;
// do some complicated things
// loop {
// loop {
f(c_iv, other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something(const T& a, F& f)
{
return do_something_impl<T,F>(a, f);
}
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
return do_something_impl<T,const F>(a, f);
}
Demo: http://ideone.com/owj6oB
The wrapper should be completely inlined and have no runtime cost at all, except for the fact that you might end up with more template instantiations (and therefore larger code size), though that will only happen when for types with no operator()() const where both const (or temporary) and non-const functors get passed.
Answer for new relaxed requirements.
In commentary on another answer the OP has clarified/changed the requirements to…
“I'm ok with requiring that if the functor is passed in as a temporary
then it must have an operator() const. I just don't want to limit it
to that, such that if a functor is not passed in as a temporary (and
also not a const non-temporary, of course) then it is allowed to have
a non-const operator(), and this will be called”
This is then not a problem at all: just provide an overload that accepts a temporary.
There are several ways of distinguishing the original basic implementation, e.g. in C++11 an extra default template argument, and in C++03 an extra defaulted ordinary function argument.
But the most clear is IMHO to just give it a different name and then provide an overloaded wrapper:
template<typename T, typename F>
size_t do_something_impl( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something( T const& a, F const& f)
{ return do_something_impl( a, f ); }
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{ return do_something_impl( a, f ); }
Note: there's no need to specify the do_something_impl instantiation explicitly, since it's inferred from the lvalue arguments.
The main feature of this approach is that it supports simpler calls, at the cost of not supporting a temporary as argument when it has non-const operator().
Original answer:
Your main goal is to avoid copying of the functor, and to accept a temporary as actual argument.
In C++11 you can just use an rvalue reference, &&
For C++03 the problem is a temporary functor instance as actual argument, where that functor has non-const operator().
One solution is to pass the burden to the client code programmer, e.g.
require the actual argument to be an lvalue, not a temporary, or
require explicit specification that the argument is a temporary, then take it as reference to const and use const_cast.
Example:
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
enum With_temp { with_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_temp, F const& f )
{
return do_something( a, const_cast<F&>( f ) );
}
If it is desired to directly support temporaries of const type, to ease the client code programmer's life also for this rare case, then one solution is to just add an additional overload:
enum With_const_temp { with_const_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_const_temp, F const& f )
{
return do_something( a, f );
}
Thanks to Steve Jessop and Ben Voigt for discussion about this case.
An alternative and much more general C++03 way is to provide the following two little functions:
template< class Type >
Type const& ref( Type const& v ) { return v; }
template< class Type >
Type& non_const_ref( Type const& v ) { return const_cast<T&>( v ); }
Then do_something, as given above in this answer, can be called like …
do_something( a, ref( MyFunctor() ) );
do_something( a, non_const_ref( MyFunctor() ) );
Why I didn't think of that immediately, in spite of having employed this solution for other things like string building: it's easy to create complexity, harder to simplify! :)
I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]