The following compiles and runs (under Apple LLVM version 6.1.0 and Visual C++ 2015):
#include <functional>
#include <iostream>
struct s { int x; };
int main(int argc, char **argv)
{
std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };
f(s {1});
return 0;
}
Why doesn't the assignment std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };
generate an error? A function accepting an rvalue reference should not have the same signature as a function accepting a const lvalue reference, should it? Dropping the const
from the lambda's declaration does generate an error as expected.
To expand on the existing comment and answer:
The point of std::function<R(A...)>
is that it can wrap any function or functor that can be called with A...
and have the result stored in an R
.
So, for example,
std::function<int(int)> f = [](long l) { return l; };
is just peachy.
So what you have to ask yourself when you see something like this: if you have a lambda taking const T &
, and you have an expression of type T &&
(or, more accurately, you have an xvalue of type T
), can you use that expression to call the lambda?
Yes, you can.
And if you can, then std::function
is supposed to be able to store that functor. That's pretty much the main point of std::function
.
Please take this with a grain of salt. This is what I understand, but I am not sure.
Consider the following output:
int main(int argc, char **argv)
{
std::cout << std::is_convertible<s &&, s&>::value << std::endl; //false
std::cout << std::is_convertible<s &&, const s&>::value << std::endl; //true
std::cout << std::is_convertible<const s &, s&&>::value << std::endl; //false
return 0;
}
This shows that it is possible to convert a s &&
to a const s&
. This is why the std::function
's assignment is ok.
Dropping the const from the lambda's declaration does generate an
error as expected.
Indeed this is because (as shown before), converting a s &&
to a s &
is not possible.
In the same way, trying the opposite:
std::function<void (const s &)> f = [](s &&p) { std::cout << p.x; };
would fail because it is not possible to convert a const s&
to a s &&
.