I still do not understand the behavior of std::optional in the following code:
class A
{
public:
// A(int x, int y) : x(x), y(y) {} // always compiles
private:
A(int x, int y) : x(x), y(y) {} // does not compile if using o.emplace(x, y)
friend std::optional<A> makeA(int x, int y);
int x, y;
};
std::optional<A> makeA(int x, int y)
{
std::optional<A> o;
if (x != 0 && y != 0) {
return A(x, y);
// o.emplace(x, y);
}
return o;
}
If I make the constructor of A as public then in makeA(...) I can use either return A(x, y) or o.emplace(x, y), boths compile.
But if I make the constructor of A private then o.emplace(x, y) will not compile. As far as I understand from reading the message error of templates:
error: no matching function for call to ‘std::optional<A>::emplace(int&, int&)’
70 | o.emplace(x, y);
| ~~~~~~~~~^~~~~~
In file included from test.cpp:2:
/usr/include/c++/11/optional:871:9: note: candidate: ‘template<class ... _Args> std::enable_if_t<is_constructible_v<_Tp, _Args ...>, _Tp&> std::optional<_Tp>::emplace(_Args&& ...) [with _Args = {_Args ...}; _Tp = A]’
871 | emplace(_Args&&... __args)
| ^~~~~~~
/usr/include/c++/11/optional:871:9: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/11/bits/move.h:57,
from /usr/include/c++/11/bits/stl_pair.h:59,
from /usr/include/c++/11/bits/stl_algobase.h:64,
from /usr/include/c++/11/memory:63,
from test.cpp:1:
/usr/include/c++/11/type_traits: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = A&]’:
/usr/include/c++/11/optional:871:2: required by substitution of ‘template<class ... _Args> std::enable_if_t<is_constructible_v<A, _Args ...>, A&> std::optional<A>::emplace<_Args ...>(_Args&& ...) [with _Args = {int&, int&}]’
test.cpp:70:14: required from here
/usr/include/c++/11/type_traits:2579:11: error: no type named ‘type’ in ‘struct std::enable_if<false, A&>’
2579 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~
In file included from test.cpp:2:
/usr/include/c++/11/optional:883:9: note: candidate: ‘template<class _Up, class ... _Args> std::enable_if_t<is_constructible_v<_Tp, std::initializer_list<_Up>&, _Args ...>, _Tp&> std::optional<_Tp>::emplace(std::initializer_list<_Up>, _Args&& ...) [with _Up = _Up; _Args = {_Args ...}; _Tp = A]’
883 | emplace(initializer_list<_Up> __il, _Args&&... __args)
| ^~~~~~~
/usr/include/c++/11/optional:883:9: note: template argument deduction/substitution failed:
test.cpp:70:14: note: mismatched types ‘std::initializer_list<_Tp>’ and ‘int’
70 | o.emplace(x, y);
the class A is not constructible. But how is it possible?
emplaceto be some kind of "magic" that doesnt need to call the constructor, or maybe something else ...return A(...)works theno.emplace(...)works (I suppose that sincemakeAis a friend then anything under its context is also friend ofA).