Given the following code:
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 0;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "value: " << my_opt.value() << std::endl;
}
gcc 7.2.0 writes value: 1
.
MSVC 2017 (15.3) and clang 4.0.0 however write value: 0
.
Which one is correct according to the C++ standard?
Since this is direct-initialization, we enumerate the constructors and just pick the best one. The relevant constructors for
std::optional
are :Both are viable (
(8)
only participates in overload resolution ifint
is constructible fromfoo&
andfoo
is neitherstd::in_place_t
norstd::optional<int>
, all of which hold), but(8)
is an exact match whereas(2)
and(3)
require a user-defined conversion, so it should be preferred. gcc is wrong here.However, gcc doesn't actually invoke
(3)
either. It just directly initializesmy_opt
from the result of convertingmy_foo
to anoptional<int>
. This program with gcc 7.2 prints3
but none of1a
,1b
, or2
:I don't think that's an allowable route. I filed 81952.