Forwarding vs not Forwarding a function passed to a wrapper - c++

My question is what is the advantage of perfect forwarding a function, which is passed to our wrapper.
template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
{
std::cout<<"timing void function"<<std::endl;
//std::forward<T>(func)(std::forward<U>(args)...); //this vs next one
func(std::forward<U>(args)...);
std::cout<<"timing over"<<std::endl;
}
In the case of argument forwarding, it is clear that forwarding preserves the lvalueness vs rvalueness of the argument. However, is there any use to forward func before calling?
Let's say I pass both temporary functors and normal functions to the time_function wrapper.

Suppose that I have a stateful assignor functor. The assignor will be reused multiple times, so it has to copy the value each time. However, if the assignor is an rvalue, it can just move the value:
struct Assignor {
std::string value;
void operator()(std::string& dest) const &
{
dest = value;
}
void operator()(std::string& dest) &&
{
dest = std::move(value);
}
};
Now, perfect forwarding makes a difference on rvalues:
Assignor f{std::string(10000, 'X')};
std::string a, b, c;
time_function(f, a); // copies the string
time_function(std::move(f), b); // should move the string
// but copies if you don't std::forward
time_function(Assignor{std::string(10000, 'Y')}, c); // same
(This is just an example of how a functor can be optimized w.r.t. value category. I know it looks a bit artificial, but people always come up with creative ideas.)
By the way, you should be using std::invoke instead of directly calling ():
std::invoke(std::forward<T>(func), std::forward<U>(args)...);

In addition to L.F.'s answer I want to make a small note about a potential problem, that is obvious but can still be overlooked: sometimes it is dangerous to pass functional objects by a universal reference and invoke them as rvalues. Suppose that instead of
void time_function(T&& func, ...)
that invokes std::forward<T>(func)(...) once, you have
void for_each(T&& func, ...)
that potentially invokes std::forward<T>(func)(...) multiple times. Then after the first call, all further calls are not safe. In the L.F.'s example, this corresponds to multiple assignments from a "moved-from" state: after the first assignment, std::string value member will be left in a "valid but unspecified state", and later assignments won't do what they are expected to do (though they won't be UB). If the Assignor doesn't have the && overload of operator(), the problem won't show up.

Related

How do correctly use a callable passed through forwarding reference?

I'm used to pass lambda functions (and other callables) to template functions -- and use them -- as follows
template <typename F>
auto foo (F && f)
{
// ...
auto x = std::forward<F>(f)(/* some arguments */);
// ...
}
I mean: I'm used to pass them through a forwarding reference and call them passing through std::forward.
Another Stack Overflow user argue (see comments to this answer) that this, calling the functional two or more time, it's dangerous because it's semantically invalid and potentially dangerous (and maybe also Undefined Behavior) when the function is called with a r-value reference.
I've partially misunderstand what he means (my fault) but the remaining doubt is if the following bar() function (with an indubitable multiple std::forward over the same object) it's correct code or it's (maybe only potentially) dangerous.
template <typename F>
auto bar (F && f)
{
using A = typename decltype(std::function{std::forward<F>(f)})::result_type;
std::vector<A> vect;
for ( auto i { 0u }; i < 10u ; ++i )
vect.push_back(std::forward<F>(f)());
return vect;
}
Forward is just a conditional move.
Therefore, to forward the same thing multiple times is, generally speaking, as dangerous as moving from it multiple times.
Unevaluated forwards don't move anything, so those don't count.
Routing through std::function adds a wrinkle: that deduction only works on function pointers and on function objects with a single function call operator that is not && qualified. For these, rvalue and lvalue invocation are always equivalent if both compiles.
I'd say the general rule applies in this case. You're not supposed to do anything with a variable after it was moved/forwarded from, except maybe assigning to it.
Thus...
How do correctly use a callable passed through forwarding reference?
Only forward if you're sure it won't be called again (i.e. on last call, if at all).
If it's never called more than once, there is no reason to not forward.
As for why your snippet could be dangerous, consider following functor:
template <typename T>
struct foo
{
T value;
const T &operator()() const & {return value;}
T &&operator()() && {return std::move(value);}
};
As an optimization, operator() when called on an rvalue allows caller to move from value.
Now, your template wouldn't compile if given this functor (because, as T.C. said, std::function wouldn't be able to determine return type in this case).
But if we changed it a bit:
template <typename A, typename F>
auto bar (F && f)
{
std::vector<A> vect;
for ( auto i { 0u }; i < 10u ; ++i )
vect.push_back(std::forward<F>(f)());
return vect;
}
then it would break spectacularly when given this functor.
If you're either going to just forward the callable to another place or simply call the callable exactly once, I would argue that using std::forward is the correct thing to do in general. As explained here, this will sort of preserve the value category of the callable and allow the "correct" version of a potentially overloaded function call operator to be called.
The problem in the original thread was that the callable was being called in a loop, thus potentially invoked more than once. The concrete example from the other thread was
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(f(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(f(element));
return sequence;
}
Here, I believe that calling std::forward<F>(f)(element) instead of f(element), i.e.,
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(std::forward<F>(f)(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(std::forward<F>(f)(element));
return sequence;
}
would be potentially problematic. As far as my understanding goes, the defining characteristic of an rvalue is that it cannot explicitly be referred to. In particular, there is naturally no way for the same prvalue to be used in an expression more than once (at least I can't think of one). Furthermore, as far as my understanding goes, if you're using std::move or std::forward or whatever other way to obtain an xvalue, even on the same original object, the result will be a new xvalue every time. Thus, there also cannot possibly be a way to refer to the same xvalue more than once. Since the same rvalue cannot be used more than once, I would argue (see also comments underneath this answer) that it would generally be a valid thing for an overloaded function call operator to do something that can only be done once in case the call happens on an rvalue, for example:
class MyFancyCallable
{
public:
void operator () & { /* do some stuff */ }
void operator () && { /* do some stuff in a special way that can only be done once */ }
};
The implementation of MyFancyCallable may assume that a call that would pick the &&-qualified version cannot possibly happen more than once (on the given object). Thus, I would consider forwarding the same callable into more than one call to be semantically broken.
Of course, technically, there is no universal definition of what it actually means to forward or move an object. In the end, it's really up to the implementation of the particular types involved to assign meaning there. Thus, you may simply specify as part of your interface that potential callables passed to your algorithm must be able to deal with being called multiple times on an rvalue that refers to the same object. However, doing so pretty much goes against all the conventions for how the rvalue reference mechanism is generally used in C++, and I don't really see what there possibly would be to be gained from doing this…

'&&' in function parameter pack

I have seen multiple instances of code where function parameter pack is declared using the && notation, as shown below, but I cannot see any advantage to using this notation.
template<typename... Args>
void Function(Args... args)
{
}
template<typename... Args>
void Function(Args&&... args)
{
}
My first thought was that the && form will be used exclusively for r-value objects, but this test proved that wrong:
struct Object
{
// Added bodies so I see what is being called via a step-into
Object() {}
Object(const Object&) {}
Object(Object&&) noexcept {}
Object& operator=(const Object&) { return *this; }
Object& operator=(Object&&) noexcept { return *this; }
};
Object GetObject() { Object o; return o; }
Object obj;
Function(GetObject());
Function(GetObject());
Here, VS 2017 complains that both forms of the function are viable candidates for the call.
Can someone explain what the difference is between these two, and what advantages one may have over the other please?
They are forwarding references in the parameter pack form. As for template parameter deduction, they can match any arguments, but the template parameter will be deduced differently comparing to the ordinary template parameter.
The major advantage of forwarding reference is that the lvalue/rvalue information will be preserved if used with std::forward. Thus they are used to "forward" something.
For example,
void real_foo(A const &a);
void real_foo(A &&a);
template<class... Args>
void foo_proxy_ordinary(Args... args) { real_foo(args...); }
template<class... Args>
void foo_proxy_perfect(Args&&... args) { real_foo(std::forward<Args>(args)...); }
The ordinary version will always call real_foo(A const &) version, because inside foo_proxy, args are always lvalue.
However, the perfect version will select real_foo(A&&) if the arguments passed in are indeed rvalues.
Combining forwarding reference with parameter pack, one can write easily generic proxy functions without performance loss in terms of lvalue/rvalue.
T&& when used in the context of
template<typename T>
void f(T&& t);
is called a forwarding reference sometimes also called a universal reference.
Main advantage of a forwarding reference is that combined with std::forward it enables achieving a so-called perfect forwarding: function template passing its arguments to another function as they are (lvalue as lvalue, rvalue as rvalue).
Now it is possible to create higher-order functions that take other functions as arguments or return them, or superior function-wrappers (e.g., std::make_shared), and do other cool things.
Here is some material that explains it much better and in more detail than I possibly can:
Perfect forwarding and universal references in C++
Rvalue References and Perfect Forwarding in C++0x
Forwarding references proposal
SO: Advantages of using forward
SO: Perfect forwarding - what's it all about?
Can someone explain what the difference is between these two, and what advantages one may have over the other please?
The difference is same for parameter packs as it is for individual parameters. Args declares an "object parameter" (pass by value) and Args&& declares a reference parameter (pass by reference).
Passing by reference allows one to avoid copying the argument when that is unnecessary. It also allows modifying the referred argument if the reference is non-const, which includes the possibility of moving from that object.
Passing by value makes it clear to the caller that the passed object will neither be modified, nor be referred to as a result of calling the function.
My first thought was that the && form will be used exclusively for r-value objects
As your test demonstrates, that is indeed an incorrect assumption. When Args is a deduced type i.e. auto or a template argument, Args&& can indeed be either an l-value reference or an r-value reference. Which one it is depends on what Args is deduced to be. This demonstrates the reference collapsing rules concisely:
typedef int& lref;
typedef int&& rref;
int n;
lref& r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int& note this case in particular
rref& r3 = n; // type of r3 is int&
rref&& r4 = 1; // type of r4 is int&&
Using such reference allows forwarding i.e. re-binding into a new lvalue reference (when possible) or moving from the object (when possible) or copying (when neither of the previous is possible).
Because of this, Args&& is called a forwarding reference (or a universal reference) when Args is a deduced type.

Forwarding the same value to two or more functions

When using forwarding references, is it a bad idea to forward the
same value to more than one function? Consider the following piece of code:
template<typename Container>
constexpr auto
front(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).front(); }
template<typename Container>
constexpr auto
back(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).back(); }
template<typename Container>
constexpr auto
get_corner(Container&& c)
{
return do_something(front(std::forward<Container(c)),
back(std::forward<Container>(c));
}
If Container is an lvalue-reference, the function works just fine. However, I'm worrying about situations where rvalues are passed on to it, because the value would get invalidated once a move occurs. My doubt is: Is there a correct way to forward the container in that case, without losing the value category?
In general, it is not reasonable for the same function to forward the same parameter twice. Not unless it has specific knowledge of what the receiver of that forwarded parameter will do.
Remember: the behavior of std::forward can be equivalent to the behavior of std::move, depending on what parameter the user passed in. And the behavior of an xvalue will be contingent on how the receiving function processes it. If the receiver takes a non-const rvalue reference, it will likely move from that value if possible. That would leave you holding a moved-from object. If it takes a value, it will certainly move from it if the type supports it.
So unless you have specific knowledge of the expected behavior of the operations you are using, it is not safe to forward a parameter more than once.
There's actually no rvalue-reference version of std::begin - we just have (setting aside constexpr and return values):
template <class C>
??? begin(C& );
template <class C>
??? begin(C const& );
For lvalue containers, you get iterator, and for rvalue containers, you get const_iterator (or whatever the container-specific equivalent ends up being).
The one real problem in your code is returning decltype(auto). For lvalue containers, that's fine - you'll return a reference to an object whose lifetime exceeds the function. But for rvalue containers, that's returning a dangling reference. You'll want to return a reference for lvalue containers and a value for rvalue containers.
On top of that, forward-ing the containers into begin()/end() is probably not what you want to do. It'd be more efficient to conditionally wrap the result of the select() as a move iterator. Something like this answer of mine:
template <typename Container,
typename V = decltype(*std::begin(std::declval<Container&>())),
typename R = std::conditional_t<
std::is_lvalue_reference<Container>::value,
V,
std::remove_reference_t<V>
>
>
constexpr R operator()(Container&& c)
{
auto it = select(std::begin(c), std::end(c));
return *make_forward_iterator<Container>(it);
}
There's probably a less verbose way to express all of that.
You presumably realize that you wouldn't want to std::move an object being passed to multiple functions:
std::string s = "hello";
std::string hello1 = std::move(s);
std::string hello2 = std::move(s); // hello2 != "hello"
The role of forward is simply to restore any rvalue status that a parameter had when it was passed to the function.
We can quickly demonstrate that it is bad practice by forwarding one parameter two times to a function that has a move effect:
#include <iostream>
#include <string>
struct S {
std::string name_ = "defaulted";
S() = default;
S(const char* name) : name_(name) {}
S(S&& rhs) { std::swap(name_, rhs.name_); name_ += " moved"; }
};
void fn(S s)
{
std::cout << "fn(" << s.name_ << ")\n";
}
template<typename T>
void fwd_test(T&& t)
{
fn(std::forward<T>(t));
fn(std::forward<T>(t));
}
int main() {
fwd_test(S("source"));
}
http://ideone.com/NRM8Ph
If forwarding was safe, we should see fn(source moved) twice, but instead we see:
fn(source moved)
fn(defaulted moved)
In general, yes, this is potentially dangerous.
Forwarding a parameter ensures that if the value received by the universal reference parameter is an rvalue of some sort, it will continue to be an rvalue when it is forwarded. If the value is ultimately forwarded to a function (such as a move-constructor) that consumes the value by moving from it, its internal state is not likely to be valid for use in subsequent calls.
If you do not forward the parameter, it will not (in general) be eligible for move operations, so you would be safe from such behavior.
In your case, front and back (both the free functions and the member functions) do not perform a move on the container, so the specific example you gave should be safe. However, this also demonstrates that there's no reason to forward the container, since an rvalue won't be given different treatment from an lvalue--which is the only reason to preserve the distinction by forwarding the value in the first place.

Setters in template classes

I'm trying to find a good way to write a setter function for a template class. For non-template classes if somehow trivial because the function signature/implementation depends on parameter type. For example if the parameter type is int the next function should be optimal:
void MyClass::Set(int value)
{
myValue = value;
}
If the parameter type is std::vector next implementation should be close to optimal:
void MyClass::Set(std::vector<SomeType> value)
{
std::swap(myValue, value);
}
as the right constructor (move or copy) will be used to construct the function parameter and no unnecessary copying occurs, assuming move constructor cost is negligible.
As you can see both implementations have drawbacks when the type is changed: If the type is changed to std::vector for the first version, at least one unnecessary copy is made increasing the actual cost by a factor of 2 or 3.
If the type changed to int in the second version 2 unnecessary copies are made, increasing the actual cost by a factor of 3.
Can you please give me a good generic implementation for a setter function (maybe with overloads)? It should be optimal/close to optimal for any type used as parameter.
PS: I would prefer to not use std::enable_if to make several type dependent setters as the class will increase dramatically.
You can use a forwarding reference to accept either an rvalue or an lvalue, then forward that to the appropriate move or copy assignment operator:
template <typename T>
void Set(T && value) {
myValue = std::forward<T>(value);
}
You should have 3 overloads.
void Set( T&& t ) {
v = std::move(t);
}
void Set( T const& t ) {
v = t;
}
template<class U>
void Set( U&& u ) {
v = std::forward<U>(u);
}
the first two allow implicit conversion to work well, if the caller uses {} initialization on the argument, or if the caller is the name of a function and it needs a context, or a few other cases: it will work. This fixes some of the bigger annoyances with "perfect forwarding".
The third gives you anything for which your operator= is overloaded to handle that isn't covered by the first two. It is an example of "perfect forwarding", which as the name implies is imperfect.
The most common problem if you only use the 3rd overload, .Set( {construction args} ) doesn't work.
Possibly the const& overload is redundant, but I am unsure.
live example
// and sometimes:
template<class...Us>
void Set( Us&&...us ) {
v = {std::forward<Us>(us)...};
}
The forth is an emplace-set. This is not actually useful in this case (where we are using operator=), but in some cases it can be. For an example of where such an emplace-accessor is useful, optional::value_or should have that overload. Basically, cases where you could directly construct the target value, or where other parameters might lead to you not constructing the value, this is useful: if you do a {std::forward<Us>(us)...} always you might as well use .Set( {args...} ) externally, which calls the first overload above.

Why use a perfectly forwarded value (a functor)?

C++11 (and C++14) introduces additional language constructs and improvements that target generic programming. These include features such as;
R-value references
Reference collapsing
Perfect forwarding
Move semantics, variadic templates and more
I was browsing an earlier draft of the C++14 specification (now with updated text) and the code in an example in §20.5.1, Compile-time integer sequences, that I found interesting and peculiar.
template<class F, class Tuple, std::size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices = make_index_sequence<std::tuple_size<Tuple>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices());
}
Online here [intseq.general]/2.
Question
Why was the function f in apply_impl being forwarded, i.e. why std::forward<F>(f)(std::get...?
Why not just apply the function as f(std::get...?
In Brief...
The TL;DR, you want to preserve the value category (r-value/l-value nature) of the functor because this can affect the overload resolution, in particular the ref-qualified members.
Function definition reduction
To focus on the issue of the function being forwarded, I've reduced the sample (and made it compile with a C++11 compiler) to;
template<class F, class... Args>
auto apply_impl(F&& func, Args&&... args) -> decltype(std::forward<F>(func)(std::forward<Args>(args)...)) {
return std::forward<F>(func)(std::forward<Args>(args)...);
}
And we create a second form, where we replace the std::forward(func) with just func;
template<class F, class... Args>
auto apply_impl_2(F&& func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
return func(std::forward<Args>(args)...);
}
Sample evaluation
Evaluating some empirical evidence of how this behaves (with conforming compilers) is a neat starting point for evaluating why the code example was written as such. Hence, in addition we will define a general functor;
struct Functor1 {
int operator()(int id) const
{
std::cout << "Functor1 ... " << id << std::endl;
return id;
}
};
Initial sample
Run some sample code;
int main()
{
Functor1 func1;
apply_impl_2(func1, 1);
apply_impl_2(Functor1(), 2);
apply_impl(func1, 3);
apply_impl(Functor1(), 4);
}
And the output is as expected, independent of whether an r-value is used Functor1() or an l-value func when making the call to apply_impl and apply_impl_2 the overloaded call operator is called. It is called for both r-values and l-values. Under C++03, this was all you got, you could not overload member methods based on the "r-value-ness" or "l-value-ness" of the object.
Functor1 ... 1
Functor1 ... 2
Functor1 ... 3
Functor1 ... 4
Ref-qualified samples
We now need to overload that call operator to stretch this a little further...
struct Functor2 {
int operator()(int id) const &
{
std::cout << "Functor2 &... " << id << std::endl;
return id;
}
int operator()(int id) &&
{
std::cout << "Functor2 &&... " << id << std::endl;
return id;
}
};
We run another sample set;
int main()
{
Functor2 func2;
apply_impl_2(func2, 5);
apply_impl_2(Functor2(), 6);
apply_impl(func2, 7);
apply_impl(Functor2(), 8);
}
And the output is;
Functor2 &... 5
Functor2 &... 6
Functor2 &... 7
Functor2 &&... 8
Discussion
In the case of apply_impl_2 (id 5 and 6), the output is not as may have been initially been expected. In both cases, the l-value qualified operator() is called (the r-value is not called at all). It may have been expected that since Functor2(), an r-value, is used to call apply_impl_2 the r-value qualified operator() would have been called. The func, as a named parameter to apply_impl_2, is an r-value reference, but since it is named, it is itself an l-value. Hence the l-value qualified operator()(int) const& is called in both the case of the l-value func2 being the argument and the r-value Functor2() being used as the argument.
In the case of apply_impl (id 7 and 8) the std::forward<F>(func) maintains or preserves the r-value/l-value nature of the argument provided for func. Hence the l-value qualified operator()(int) const& is called with the l-value func2 used as the argument and the r-value qualified operator()(int)&& when the r-value Functor2() is used as the argument. This behaviour is what would have been expected.
Conclusions
The use of std::forward, via perfect forwarding, ensures that we preserve the r-value/l-value nature of the original argument for func. It preserves their value category.
It is required, std::forward can and should be used for more than just forwarding arguments to functions, but also when the use of an argument is required where the r-value/l-value nature must be preserved. Note; there are situations where the r-value/l-value cannot or should not be preserved, in these situations std::forward should not be used (see the converse below).
There are many examples popping up that inadvertently lose the r-value/l-value nature of the arguments via a seemingly innocent use of an r-value reference.
It has always been hard to write well defined and sound generic code. With the introduction of r-value references, and reference collapsing in particular, it has become possible to write better generic code, more concisely, but we need to be ever more aware of what the original nature of the arguments provided are and make sure that they are maintained when we use them in the generic code we write.
Full sample code can be found here
Corollary and converse
A corollary of the question would be; given reference collapsing in a templated function, how is the r-value/l-value nature of the argument maintained? The answer - use std::forward<T>(t).
Converse; does std::forward solve all your "universal reference" problems? No it doesn't, there are cases where it should not be used, such as forwarding the value more than once.
Brief background to perfect forwarding
Perfect forwarding may be unfamiliar to some, so what is perfect forwarding?
In brief, perfect forwarding is there to ensure that the argument provided to a function is forwarded (passed) to another function with the same value category (basically r-value vs. l-value) as originally provided. It is typically used with template functions where reference collapsing may have taken place.
Scott Meyers gives the following pseudo code in his Going Native 2013 presentation to explain the workings of std::forward (at approximately the 20 minute mark);
template <typename T>
T&& forward(T&& param) { // T&& here is formulated to disallow type deduction
if (is_lvalue_reference<T>::value) {
return param; // return type T&& collapses to T& in this case
}
else {
return move(param);
}
}
Perfect forwarding depends on a handful of fundamental language constructs new to C++11 that form the bases for much of what we now see in generic programming:
Reference collapsing
Rvalue references
Move semantics
The use of std::forward is currently intended in the formulaic std::forward<T>, understanding how std::forward works helps understand why this is such, and also aids in identifying non-idiomatic or incorrect use of rvalues, reference collapsing and ilk.
Thomas Becker provides a nice, but dense write up on the perfect forwarding problem and solution.
What are ref-qualifiers?
The ref-qualifiers (lvalue ref-qualifier & and rvalue ref-qualifier &&) are similar to the cv-qualifiers in that they (the ref-qualified members) are used during overload resolution to determine which method to call. They behave as you would expect them to; the & applies to lvalues and && to rvalues. Note: Unlike cv-qualification, *this remains an l-value expression.
Here is a practical example.
struct concat {
std::vector<int> state;
std::vector<int> const& operator()(int x)&{
state.push_back(x);
return state;
}
std::vector<int> operator()(int x)&&{
state.push_back(x);
return std::move(state);
}
std::vector<int> const& operator()()&{ return state; }
std::vector<int> operator()()&&{ return std::move(state); }
};
This function object takes an x, and concatenates it to an internal std::vector. It then returns that std::vector.
If evaluated in an rvalue context it moves to a temporary, otherwise it returns a const& to the internal vector.
Now we call apply:
auto result = apply( concat{}, std::make_tuple(2) );
because we carefully forwarded our function object, only 1 std::vector buffer is allocated. It is simply moved out to result.
Without the careful forwarding, we end up creating an internal std::vector, and we copy it to result, then discard the internal std::vector.
Because the operator()&& knows that the function object should be treated as a rvalue about to be destroyed, it can rip the guts out of the function object while doing its operation. The operator()& cannot do this.
Careful use of perfect forwarding of function objects enables this optimization.
Note, however, that there is very little use of this technique "in the wild" at this point. Rvalue qualified overloading is obscure, and doing so to operator() moreso.
I could easily see future versions of C++ automatically using the rvalue state of a lambda to implicitly move its captured-by-value data in certain contexts, however.