Reputation: 8401
Given a code:
constexpr auto a = std::make_array<size_t>(1, 2, 3);
Clang (3.7) with a realization copied from GCC's libstdc++v3 experimental/array gives this warning:
error: non-constant-expression cannot be narrowed from type 'int' to 'value_type' (aka 'unsigned long') in initializer list [-Wc++11-narrowing]
return {{ std::forward<Types>(t)... }};
Is this legal when a compiler knows at compile-time, that 1, 2 and 3 can be implicitly converted to size_t
?
It gives no warning when I write:
constexpr std::array<size_t, 3> a{1, 2, 3};
And std::make_array
is supposed to be the same as this construction.
It is more theoretical than practical question.
Bonus question: how can std::make_array
be corrected in GCC's realization to accept code given above?
GCC's realization:
template <typename _Dest = void, typename... _Types>
constexpr auto
make_array(_Types&&... __t)
-> array<conditional_t<is_void_v<_Dest>,
common_type_t<_Types...>,
_Dest>,
sizeof...(_Types)>
{
static_assert(__or_<
__not_<is_void<_Dest>>,
__and_<__not_<__is_reference_wrapper<decay_t<_Types>>>...>>
::value,
"make_array cannot be used without an explicit target type "
"if any of the types given is a reference_wrapper");
return {{forward<_Types>(__t)...}};
}
Upvotes: 1
Views: 645
Reputation:
No, std::make_array
is not supposed to be the same as that construction.
std::make_array
takes Types&&...
, which requires determining the types from the arguments, and in your case produces parameters of type int
. Inside make_array
, you no longer have constant values, so the exception that in-range constant integer values can be converted inside {}
no longer applies.
A different example is std::array<void*, 1>{0}
vs. std::make_array<void*>(0)
. The former is valid, since 0
is convertible to any pointer type. The latter is invalid, since an integer parameter which happens to have the value 0
is not implicitly convertible to any pointer type.
Upvotes: 3