我可以使用std :: initializer_list而不是大括号括起初始化器来初始化数组吗?

Ale*_*lex 12 c++ initializer-list c++11 c++14 c++17

我可以使用std::initializer_list对象而不是大括号括起初始化器来初始化数组吗?

众所周知,我们可以这样做:http://en.cppreference.com/w/cpp/language/aggregate_initialization

unsigned char b[5]{"abc"};
// equivalent to unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};

int ar[] = {1,2,3};
std::array<int, 3> std_ar2{ {1,2,3} };    // std::array is an aggregate
std::array<int, 3> std_ar1 = {1, 2, 3};
Run Code Online (Sandbox Code Playgroud)

但我不能通过以下方式初始化数组std::initializer_list il;:

http://ideone.com/f6aflX

#include <iostream>
#include <initializer_list>
#include <array>

int main() {

    int arr1[] =  { 1, 2, 3 };  // OK
    std::array<int, 3> arr2 =  { 1, 2, 3 }; // OK

    std::initializer_list<int> il = { 1, 2, 3 };
    constexpr std::initializer_list<int> il_constexpr = { 1, 2, 3 };

    //int arr3[] = il;  // error
    //int arr4[] = il_constexpr;    // error

    //std::array<int, 3> arr5 =  il;    // error
    //std::array<int, 3> arr6 =  il_constexpr;  // error

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是如何使用std::initializer_list il;初始化数组呢?

Joh*_*itb 9

其他正确答案说这是不可能的.但是有了很少的帮助,你可以非常接近

template<typename T, std::size_T N, std::size_t ...Ns>
std::array<T, N> make_array_impl(
    std::initializer_list<T> t,
    std::index_sequence<Ns...>) 
{
    return std::array<T, N>{ *(t.begin() + Ns) ... };
}

template<typename T, std::size_t N>
std::array<T, N> make_array(std::initializer_list<T> t) {
    if(N > t.size())
       throw std::out_of_range("that's crazy!");
    return make_array_impl<T, N>(t, std::make_index_sequence<N>());
}
Run Code Online (Sandbox Code Playgroud)

如果您对更多的解决方法持开放态度,可以将其放入类中,以便在传递支撑初始化列表的情况下捕获静态已知的长度违例.但要注意的是,阅读此代码的大多数人都会在前台工作

template<typename T, std::size_t N>
struct ArrayInitializer {
    template<typename U> struct id { using type = U; };
    std::array<T, N> t;

    template<typename U = std::initializer_list<T>>
    ArrayInitializer(typename id<U>::type z) 
        :ArrayInitializer(z, std::make_index_sequence<N>())
    { 
        if(N > z.size())
            throw std::out_of_range("that's crazy!");
    }

    template<typename ...U>
    ArrayInitializer(U &&... u)
       :t{ std::forward<U>(u)... }
    { }

private:
    template<std::size_t ...Ns>
    ArrayInitializer(std::initializer_list<T>& t,
                     std::index_sequence<Ns...>)
       :t{ *(t.begin() + Ns) ... }
    { }
};

template<typename T, std::size_t N>
std::array<T, N> f(ArrayInitializer<T, N> ai) {
    return std::move(ai.t);
}

int main() {
   f<int, 5>({1, 2, 3, 4, 5});  // OK 
   f<int, 5>({1, 2, 3, 4, 5, 6});  // "too many initializers for array<int, 5>"

   std::initializer_list<int> il{1, 2, 3, 4, 5};
   f<int, 5>(il); // ok
}
Run Code Online (Sandbox Code Playgroud)

请注意,答案顶部的非静态案例和"head-desk"案例只会检查您是否提供的初始化元素太少,而且出现错误initializer_list.如果为这种initializer_list情况提供太多,则只会忽略尾随元素.


max*_*x66 6

据我所知,不,你不能初始化std::arraya std::initializer_list.

问题在于它std::array是用于经典C风格数组的轻量级替换(包装器).所以没有构造函数的光,所以只能使用隐式构造函数.

具有聚合初始化(通过隐式构造函数)的构造是可能的,因为它可以用于C样式的数组.

但这std::initializer_list是一个类,比集合的inizialization更复杂.

您可以通过示例初始化a std::vector,std::initializer_list但仅因为有一个显式构造函数,用于std::vector接收a std::initializer_list.但是std::vector是一个更重的课程.

我看到的唯一解决方案是两步法:(1)构造和(2)std::initializer_list值的复制.就像是

std::array<int, 3> arr5;

auto  ui = 0U;
auto  cit = il.cbegin();

while ( (ui < arr5.size()) && (cit != il.cend()) )
   arr5[ui++] = *cit++;
Run Code Online (Sandbox Code Playgroud)

ps:抱歉我的英语不好.

  • _Bad English?_你写得比大多数同事都好.在Stack溢出答案或问题中,您不需要这样的评论.社区将编辑任何不可理解的内容. (7认同)
  • @AndonM.Coleman - 谢谢;我会尝试忽略我的语言不安全感。 (2认同)