How to create std::array with initialization list without providing size directly

C++InitializationStdarray

C++ Problem Overview


How can I make a3 compile?

int main()
{
	int a1[] = { 1, 2, 3 };
	std::array<int, 3> a2 = { 1, 2, 3 };
	std::array<int> a3 = { 1, 2, 3 };
}

It's very inconvenient, and brittle, to hard-code the size of the array when using an initialization list, especially long ones. Is there any work around? I hope so otherwise I'm disappointed because I hate C arrays and std::array is supposed to be their replacement.

C++ Solutions


Solution 1 - C++

There is currently no way to do this without rolling your own make_array, there is a proposal for this N3824: make_array which has the following scope:

>LWG 851 intended to provide a replacement syntax to > > array a = { E1, E2, ... }; > >, so the following > > auto a = make_array(42u, 3.14); > >is well-formed (with additional static_casts applied inside) because > > array = { 42u, 3.14 }; > >is well-formed. > > This paper intends to provide a set of std::array creation interfaces > which are comprehensive from both tuple’s point of view and array’s > point of view, so narrowing is just naturally banned. See more details > driven by this direction in Design Decisions.

It also includes a sample implementation, which is rather long so copying here is impractical but Konrad Rudolph has a simplified version here which is consistent with the sample implementation above:

template <typename... T>
constexpr auto make_array(T&&... values) ->
    std::array<
       typename std::decay<
           typename std::common_type<T...>::type>::type,
       sizeof...(T)> {
    return std::array<
        typename std::decay<
            typename std::common_type<T...>::type>::type,
        sizeof...(T)>{std::forward<T>(values)...};
}

Solution 2 - C++

You're being a little overdramatic when you say "such a horribly complex (to me) function is required". You can make a simplified version yourself, the proposal also includes a "to_array" function to convert C-arrays and deducing the type from the first parameter. If you leave that out it gets quite manageable.

template<typename T, typename... N>
auto my_make_array(N&&... args) -> std::array<T,sizeof...(args)>
{
	return {std::forward<N>(args)...};
}

which you can then call like

auto arr = my_make_array<int>(1,2,3,4,5);

edit: I should mention that there actually is a version of that in the proposal that I overlooked, so this should be more correct than my version:

template <typename V, typename... T>
constexpr auto array_of(T&&... t)
	-> std::array < V, sizeof...(T) >
{
	return {{ std::forward<T>(t)... }};
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNeil KirkView Question on Stackoverflow
Solution 1 - C++Shafik YaghmourView Answer on Stackoverflow
Solution 2 - C++PeterTView Answer on Stackoverflow