Update: This is a C++ standard defect, which is fixed in C++20 (P0608R3). Also, VS 2019 16.10 has fixed this bug with /std:c++20
.
MSVC 19.28 rejects the following code but gcc 10.2 accepts it and outputs true false
#include <iostream>
#include <variant>
int main()
{
std::variant<long long, double> v{ 0 };
std::cout << std::boolalpha << std::holds_alternative<long long>(v) << ' ' << std::holds_alternative<double>(v) << std::endl;
}
According to cppreference:
- Converting constructor. Constructs a variant holding the alternative type
T_j
that would be selected by overload resolution for the expressionF(std::forward<T>(t))
if there was an overload of imaginary functionF(T_i)
for everyT_i
fromTypes...
in scope at the same time, except that: An overloadF(T_i)
is only considered if the declarationT_i x[] = { std::forward<T>(t) };
is valid for some invented variablex
; Direct-initializes the contained value as if by direct non-list-initialization fromstd::forward<T>(t)
.
And the question is converted to which function of F(long long)
and F(double)
is selected agianst argument 1
by overload resolution.
Converting int
to long long
is an integral conversion (supposing sizeof(long long)
is bigger than sizeof(int)
) and converting int
to double
is an floating-integral conversion, neither ranks higher that the other. So the call is ambiguous and the program is ill-formed.
MSVC does rejected the code as I expected but to my surprise, gcc accepts it. Besides, there is also a similar example on cppreference:
std::variant<std::string> v("abc"); // OK
std::variant<std::string, std::string> w("abc"); // ill-formed
std::variant<std::string, const char*> x("abc"); // OK, chooses const char*
std::variant<std::string, bool> y("abc"); // OK, chooses string; bool is not a candidate
/* THIS ONE -> */ std::variant<float, long, double> z = 0; // OK, holds long
// float and double are not candidates
So my question is: is gcc or MSVC non-conformance, or my understanding is wrong?