Reputation: 4189
I can create std::function
that returns std::optional<Foo>
and assigned lambda that returns Foo
to it. Can someone explain in details how this is possible?
simple example:
#include <iostream>
#include <optional>
#include <functional>
int main()
{
int k = 13;
std::function<std::optional<int>()> f1;
f1 = [&] {return k++;}; //implicite int
std::cout<<"k = " << f1().value() << std::endl;
f1 = [&] () -> int {return k;}; //explicite int
std::cout<<"k = " << f1().value() << std::endl;
}
Upvotes: 3
Views: 605
Reputation: 38295
The constructor of std::optional
(#8 in the overload set) is conditionally explicit, depending on the template parameter. In your case (std::optional<int>
), you can implicitly construct instances,
std::optional<int> opt;
opt = 42; /* No problem, implicit construction. */
and this exactly is what the wrapper std::function<std::optional<int>>
does. It calls the wrapped function, which returns an int
, and uses this return value to implicitly construct its own return value, std::optional<int>
.
Upvotes: 4
Reputation: 75815
In short the target assigned to std::function
must me Callable for the parameters and return type of the template parameter of std::function
.
E.g. Given:
std::function<R(P1, P2)>
p1
of type P1
p2
of type P2
You can assign a target f
to it if f(p1, p2)
is well-formed and implicitly convertible to R
. (*)
The other answers show that std::optional<int>
is implicitly constuctible from int
.
So in your example [&] () -> int {return k;}()
returns an int
and that is implicitly convertible to std::optional<int>
.
(*) Please note that this is a bit oversimplified as the rigorous definition involves the invoke function/concept
Upvotes: 2
Reputation: 63029
There is an implicit conversion from int
to std::optional<int>
.
The template constructor of std::function
uses the named requirement Callable, which only requires that the INVOKE
expression be implicitly convertible to the result type, not that they be the same type.
Upvotes: 4