Как написано в комментариях, это широкий аргумент.
Во всяком случае, я обращаю ваше внимание на точку.
В первом случае
X x1[] {{5, 6.3}};
номер элемента x1
является частью типа x1
.
Итак, у вас есть это
X x1[] {{5, 6.3}};
X x2[] {{5, 6.3}, {7, 8.1}};
static_assert( false == std::is_same<decltype(x1), decltype(x2)>::value );
Использование списка инициализаторов
std::initializer_list<X> x3 {{5, 6.3}};
std::initializer_list<X> x4 {{5, 6.3}, {7, 8.1}};
static_assert( true == std::is_same<decltype(x3), decltype(x4)>::value );
тип остается прежним при изменении количества элементов.
В зависимости от ваших потребностей это может быть преимуществом для первого или второго решения.
Тот факт, что количество элементов является частью типа для массивов в стиле C, может быть небольшим преимуществом в метапрограммировании.
Предположим, вам нужна функция, которая возвращает сумму i
значений массивов, с массивом в стиле C вы можете написать
template <std::size_t N, std::size_t ... Is>
constexpr auto sum_i_helper (X const (&xArr)[N], std::index_sequence<Is...>)
{ return (... + xArr[Is].i); }
template <std::size_t N>
constexpr auto sum_i (X const (&xArr)[N])
{ return sum_i_helper(xArr, std::make_index_sequence<N>{}); }
и эта функция компилируется также, когда аргумент sum_i()
является значением not-constexpr.
Если вы хотите написать что-то похожее с std::initializer_list
, это немного сложнее, потому что size()
списка не обязательно является известным значением времени компиляции, или вы передаёте его как параметр шаблона (но функция не не работает со списками времени выполнения) или вы используете size()
внутри функции, но вы не можете использовать его для инициализации std::index_sequence
.
В любом случае, со списком инициализаторов вы можете использовать старый добрый for()
цикл
constexpr auto sum_i (std::initializer_list<X> const lx)
{
int ret { 0 };
for ( auto const & x : lx )
ret += x.i;
return ret;
}
и функция может вычислять время компиляции, когда lx
является значением constexpr
.
Также беспокоит, сможете ли вы использовать / преобразовать один тип в другой, например. при конструировании стандартных контейнеров?
Преобразование массива в список инициализатора, это легко работает как с известным временем компиляции, так и с временем выполнения
template <std::size_t N, std::size_t ... Is>
constexpr auto convertX_h (X const (&xArr)[N], std::index_sequence<Is...>)
{ return std::initializer_list<X>{ xArr[Is]... }; }
template <std::size_t N>
constexpr auto convertX (X const (&xArr)[N])
{ return convertX_h(xArr, std::make_index_sequence<N>{}); }
// ....
X x1[] {{5, 6.3}};
std::initializer_list<X> x5 = convertX(x1);
Преобразование списка инициализатора в массив в стиле C сложнее, поскольку тип массива зависит от количества элементов, поэтому вам необходимо знать время компиляции количество элементов в списке инициализатора потому что вы не можете получить произвольный доступ к списку инициализаторов и, что еще хуже, потому что вы не можете написать функцию, которая возвращает массив в стиле C.
Я могу представить себе следующее решение, которое преобразует список инициализатора в std::array
(не по теме: используйте std::array
вместо массива в стиле C, когда это возможно)
template <std::size_t N>
constexpr auto convertX (std::initializer_list<X> const lx)
{
std::array<X, N> ret;
std::size_t i { 0u };
for ( auto const & x : lx )
ret[i++] = x;
return ret;
}
// ...
constexpr std::initializer_list<X> x4 {{5, 6.3}, {7, 8.1}};
auto x6 = convertX<x4.size()>(x4);
, но x6
теперь является std::array<X, 2>
, а не X[2]
, а x4
должно быть constexpr
.