Consider the following code:
void fnc(int)
{
std::cout << "int";
}
void fnc(long double)
{
std::cout << "long double";
}
int main()
{
fnc(42.3); // error
}
It gives an error because of an ambiguous call to fnc
.
However, if we write the next code:
std::variant<int, long double> v{42.3};
std::cout << v.index();
the output is 1
, which demonstrates that the double
->long double
conversion has been chosen.
As far as I know, std::variant
follows the C rules about conversion ranks, but this example shows the difference. Is there any explanation for such a behavior?
CodePudding user response:
Before P0608, variant<int, long double> v{42.3}
also has the ambiguous issue since 42.3
can be converted to int
or long double
.
P0608 changed the behavior of variant
's constructors:
template<class T> constexpr variant(T&& t) noexcept(see below);
- Let
Tj
be a type that is determined as follows: build an imaginary functionFUN(Ti)
for each alternative typeTi
for whichTi x[] = {std::forward<T>(t)};
is well-formed for some invented variablex
and, ifTi
iscv bool
,remove_cvref_t<T>
is bool. The overloadFUN(Ti)
selected by overload resolution for the expressionFUN(std::forward<T>(t))
defines the alternativeTj
which is the type of the contained value after construction.
In your example, the variant
has two alternative types: int
and long double
, so we can build the following expression
int x[] = {std::forward<double>(42.3)}; // #1
long double y[] = {std::forward<double>(42.3)}; // #2
Since only #2
is well-formed, the variant
successfully deduces the type of the contained value type long double
.