vladon
vladon

Reputation: 8401

std::make_array<size_t> from signed int

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

Answers (1)

user743382
user743382

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

Related Questions