Home > Enterprise >  std::variant and ambiguous initialization
std::variant and ambiguous initialization

Time:04-13

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 function FUN(Ti) for each alternative type Ti for which Ti x[] = {std::forward<T>(t)}; is well-formed for some invented variable x and, if Ti is cv bool, remove_cvref_t<T> is bool. The overload FUN(Ti) selected by overload resolution for the expression FUN(std::forward<T>(t)) defines the alternative Tj 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.

  • Related