How to emulate C array initialization "int arr[] = { e1, e2, e3, ... }" behaviour with std::array?
arrays, c++, c++11, initialization, templates
Solution
Best I can think of is:
template<class T, class... Tail>
auto make_array(T head, Tail... tail) -> std::array<T, 1 + sizeof...(Tail)>
{
std::array<T, 1 + sizeof...(Tail)> a = { head, tail ... };
return a;
}
auto a = make_array(1, 2, 3);
However, this requires the compiler to do NRVO, and then also skip the copy of returned value (which is also legal but not required). In practice, I would expect any C++ compiler to be able to optimize that such that it's as fast as direct initialization.
Problem
(Note: This question is about not having to specify the number of elements and still allow nested types to be directly initialized.) This question discusses the uses left for a C array like `int arr[20];`. On his answer, @James Kanze shows one of the last strongholds of C arrays, it's unique initialization characteristics: ``` int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 }; ``` We don't have to specify the number of elements, hooray! Now iterate over it with the C++11 functions `std::begin` and `std::end` from `<iterator>` (or your own variants) and you never need to even think of its size. Now, are there any (possibly TMP) ways to achieve the same with `std::array`? Use of macros allowed to make it look nicer. :) ``` ??? std_array = { "here", "be", "elements" }; ``` Edit: Intermediate version, compiled from various answers, looks like this: ``` #include <array> #include <utility> template<class T, class... Tail, class Elem = typename std::decay<T>::type> std::array<Elem,1+sizeof...(Tail)> make_array(T&& head, Tail&&... values) { return { std::forward<T>(head), std::forward<Tail>(values)... }; } // in code auto std_array = make_array(1,2,3,4,5); ``` And employs all kind of cool C++11 stuff: - Variadic Templates - `sizeof...` - rvalue references - perfect forwarding - `std::array`, of course - uniform initialization - omitting the return type with uniform initialization - type inference (`auto`) And an example can be found here. However, as @Johannes points out in the comment on @Xaade's answer, you can't initialize nested types with such a function. Example: ``` struct A{ int a; int b; }; // C syntax A arr[] = { {1,2}, {3,4} }; // using std::array ??? std_array = { {1,2}, {3,4} }; ``` Also, the number of initializers is limited to the number of function and template arguments supported by the implementation.
Related problems
- Narrowing conversions in C++0x. Is it just me, or does this sound like a breaking change?
- How to use std::sort to sort an array in C++
- Now that we have std::array what uses are left for C-style arrays?
- How to create std::array with initialization list without providing size directly
- Can I add a deduction guide to `std` namespace?