Logman
Logman

Reputation: 4189

How std::function<std::optional<T>()> is compatible with lambda returning T?

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

Answers (3)

lubgr
lubgr

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

bolov
bolov

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:

  • a 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

Caleth
Caleth

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

Related Questions