I'm trying to understand construction of std::variant<Ts...> by giving it a value from which one of its Ts can be constructed. The reference says
std::variant<Types...>::variant
...
(4)
template<class T> constexpr variant(T&& t) noexcept(/* see below */);...
(4) Converting constructor. Constructs a variant holding the alternative type
T_jthat would be selected by overload resolution for the expressionF(std::forward<T>(t))if there was an overload of imaginary functionF(T_i)for eachT_iinTypes..., except that narrowing conversions aren't considered.Formally: An overload
F(T_i)is only considered if the declarationT_i x[] = { std::forward<T>(t) };is valid for some invented variablex.
From that snipped, I would have expected the following to work:
using Var = std::variant<uint32_t, uint64_t>; // alias OK
([](uint32_t){})(std::forward<uint8_t>(12)); // compiles fine --> imaginary function F can be called
uint32_t x[] = {std::forward<uint8_t>(12)}; // compiles fine --> array declaration is valid
static_assert(std::is_constructible_v<Var, uint8_t>); // assertion fails
but it doesn't (the assertion fails). Is it due to the ambiguity between uint32_t and uint64_t both being constructible with uint8_t? I didn't find anything about that in the cppreference link (maybe I'm blind).
Oh, now that I stare at the passage I linked, the answer is obviously 'yes', it's because of the ambiguitiy. The reference states that F(uint32_t) should be selected if there is an overloaded F(T_i) for all T_i. Indeed, if there is F(uint32_t) and F(uint64_t), then the former will not be selected due to ambiguity.