https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123610
Bug ID: 123610
Summary: Optional empty vector prefers invalid explicit
in_place_t construction
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: harald at gigawatt dot nl
Target Milestone: ---
I'm not entirely sure if this is a valid bug, but it seems like clear enough
code that used to work that it's at least worth having a report for it.
=====
#include <optional>
#include <vector>
std::optional<std::vector<int>> foo() { return {{}}; }
=====
This was accepted up to GCC 12, but since GCC 13 it is rejected:
https://godbolt.org/z/WrxbMTfea:
<source>: In function 'std::optional<std::vector<int> > foo()':
<source>:3:51: error: converting to 'std::optional<std::vector<int> >' from
initializer list would use explicit constructor 'constexpr
std::optional<_Tp>::optional(std::in_place_t, _Args&& ...) [with _Args = {};
typename std::enable_if<__and_v<std::is_constructible<_Tp, _Args ...> >,
bool>::type <anonymous> = false; _Tp = std::vector<int>]'
3 | std::optional<std::vector<int>> foo() { return {{}}; }
| ^
<source>:3:51: error: converting to 'std::in_place_t' from initializer list
would use explicit constructor 'constexpr std::in_place_t::in_place_t()'
Compiler returned: 1
Clang, MSVC, EDG accept this.
Comments in bug 109247 suggest that GCC implements the correct intended
behaviour in the compiler and the other compilers are non-compliant, and I
think that probably applies here too: the invalid explicit
optional(std::in_place_t, Args&&...) constructor is more specialised than the
valid non-explicit optional(U&& value) constructor on account of U being a
template parameter, so technically, I think GCC is right to prefer that invalid
constructor.
At the same time though, the approach in bug 109247 was that it was okay to
implement a workaround to just make the code work. It's perfectly clear what
the user is trying to do, it works in other compilers, and there is no reason
to reject it. I hope that same approach can be taken here: it should be
perfectly clear that the intended behaviour is to construct an optional from an
empty vector, and it would be nice if that can somehow be made to work again.