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_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 eachT_i
inTypes...
, 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.