Как создать std:: array с списком инициализации без предоставления размера напрямую

Как сделать a3 компиляцию?

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

Очень неудобно и хрупко, чтобы жестко закодировать размер массива при использовании списка инициализации, особенно длинных. Есть ли какая-нибудь работа? Я надеюсь, что в противном случае я разочарован, потому что я ненавижу C-массивы и std::array должен быть их заменой.

Ответ 1

В настоящее время нет способа сделать это, не сворачивая свой собственный make_array, есть предложение для этого N3824: make_array, которое имеет следующую область:

LWG 851, предназначенный для обеспечения синтаксиса замены

array<T, N> a = { E1, E2, ... };

поэтому следующее

auto a = make_array(42u, 3.14);

хорошо сформирован (с добавлением дополнительных static_casts внутри), потому что

array<double, 2> = { 42u, 3.14 };

хорошо сформирован.

В этом документе предлагается создать набор интерфейсов создания std:: array которые являются всеобъемлющими как с точки зрения кортежей, так и с массивами точка зрения, поэтому сужение просто естественно запрещено. Подробнее управляемые этим направлением в проектных решениях.

Он также включает примерную реализацию, которая довольно длинна, поэтому копирование здесь нецелесообразно, но у Konrad Rudolph есть упрощенная версия здесь, что соответствует приведенной выше реализации выборки:

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)...};
}

Ответ 2

Ты немного переоцениваешься, когда говоришь "нужна такая ужасно сложная (мне) функция". Вы можете сделать упрощенную версию самостоятельно, предложение также включает функцию "to_array" для преобразования C-массивов и выведения типа из первого параметра. Если вы оставите это, он станет вполне управляемым.

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

который вы можете вызвать как

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

изменить: Я должен упомянуть, что на самом деле есть версия этого предложения, которое я пропустил, поэтому это должно быть более правильным, чем моя версия:

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