boost::make_optional with type specification

I’m puzzled about the boost::make_optional() behavior when used with the template specification.

In particular, it’s still unclear to me why this:

int pizza = 5;
boost::optional<int> pizza_opt = boost::make_optional<int>(pizza)

throws the compile error cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’; while this:

int foo(int bar)
{ return bar; }

boost::optional<int> pizza_opt = boost::make_optional<int>(foo(pizza))

works fine.

I already know from this that it does not make much sense to use boost::make_optional specifying the type, but I’m reading some code which does use of this structure.

Thank you!

Answer

Template parameter of boost::make_optional doesn’t define exactly type inside optional.

This template parameter is responsible for perfect forwarding, here is simple minimal example reproducing issue:

#include <iostream>

template<typename T>
void bar(T&& x)
{
    std::cout << __PRETTY_FUNCTION__ << " " 
        << std::forward<T>(x) << 'n';
}

int foo(int x)
{
    return x + 1;
}

int main()
{
    int pizza = 5;
    bar(pizza);
    bar<int>(foo(pizza));
    // bar<int>(pizza); // same error

    return 0;
}

Live demo.

So when deduction is done T is int& for l-values and int for r-values.

When you pass variable you passing l-value.

When you specified type you are forcing argument to be int && which do not match to int&.