如何从向量初始化数组? (如何将指针强制转换为数组?)

时间:2016-04-29 09:21:33

标签: c++ arrays c++11 casting

我正在尝试从std::array的数据构建std::vector。我目前这样做了:

#include <vector>
#include <array>

int main(void)
{
    std::vector<int>    vec{{1, 2, 3, 4, 5}};
    std::array<int, 5>  arr{static_cast<int [5]>(vec.data())};

    (void)arr;
    return 0;
}

但是gcc不接受这个演员:

  

错误:将类型为'int *'的static_cast无效,以输入'int [5]'

我认为数组可以用作指针,为什么我们不能这样做?

修改:这不是Copy std::vector into std::array的重复,因为我的问题是std::array初始化(构造);不要复制到它。

编辑:我这样做了:

#include <vector>
#include <array>

int main(void)
{
    std::vector<int>    vec{{1, 2, 3, 4, 5}};
    int                 *a(vec.data());
    std::array<int, 5>  arr{*reinterpret_cast<int (*)[5]>(&a)};

    (void)arr;
    return 0;
}

但数组没有初始化... gcc说:

  

错误:必须使用大括号括起初始化程序

初始化数组

4 个答案:

答案 0 :(得分:2)

“我以为数组可以用作指针,为什么我们不能这样做?”

您可以使用数组作为指针,因为它们会“衰减”到它们。见"What is array decaying?"

但事实恰恰相反。 (还有对不同大小的数组进行类型检查。)

虽然可以使用static_cast来反转某些隐式转换,但这不是其中之一。它明确excluded from the list

  

5)如果存在从new_type到表达式类型的标准转换序列,不包括左值到右值,数组到指针,函数-to-pointer,空指针,null成员指针,函数指针,(自C ++ 17)或布尔转换,然后static_cast可以执行隐式转换的反转。

因此,这可能会让您想知道如何将指针转换为数组类型。您不能,因为"Arrays are second-class citizens in C (and thus in C++)." reinterpret_cast也无效。

(如果您尝试使用像(int [5])(vec.data())这样的C风格的演员表,您可能会获得更明确的消息 ISO C ++禁止转换为数组类型'int [5]'。 )

这就是语言实现失败的原因。在这里你正在做的是尝试初始化std::array,其存在的理由只是wrap a C array

  

此容器是一种聚合类型,其语义与包含C样式数组T [N]作为其唯一非静态数据成员的结构相同。

因此,当谈到初始化表单时,它无法做任何你不能为C数组做的事情。如果你手中有一个整数指针并且希望从该指针初始化int arr[5] = ...,那么你也同样运气不好。你必须复制它。

在这种情况下可以用......完成。

Copy std::vector into std::array

答案 1 :(得分:2)

您可以使用递归模板来实现类似于您想要的内容。诀窍是使用变量模板中的...运算符将参数列表构造到数组构造函数,该变量模板具有所需的向量元素索引作为其可变参数。在实现此目的的下面的实现中,然后在模板中完成数组本身的构造,并且您可以依赖返回值优化来确保不进行复制以将值获取到最终数组中。这实现了你从矢量初始化数组的既定目标,虽然它有点人为,并不一定是你真正想做的事情。

#include <vector>
#include <array>
#include <iostream>

template<typename T, unsigned total_elem_count, unsigned remain_elem_count, unsigned... elements>
struct init_array_from_vec_helper
{   
    static std::array<T, total_elem_count> array_from_vec(const std::vector<T>& cont)
    {   
        return init_array_from_vec_helper<T, total_elem_count, remain_elem_count-1, remain_elem_count-1, elements...>::array_from_vec(cont);
    }   
};  


template<typename T, unsigned total_elem_count, unsigned... elements>
struct init_array_from_vec_helper<T, total_elem_count, 0, elements...>
{   
    static std::array<T, total_elem_count> array_from_vec(const std::vector<T>& cont)
    {   
        return std::array<T, total_elem_count>{cont[elements]...};
    }   
};  

template<typename T, unsigned total_elem_count>
std::array<T, total_elem_count> init_array_from_vec(const std::vector<T>& vec)
{   
    return init_array_from_vec_helper<int, total_elem_count, total_elem_count-1, total_elem_count-1>::array_from_vec(vec);
}   

int main(void)
{   
    std::vector<int>    vec{{1, 2, 3, 4, 5}};

    std::array<int, 5> arr(init_array_from_vec<int, 5>(vec));

    (void)arr;

    for(int i : arr)
        std::cout << i << std::endl;

    return 0;
}   

答案 2 :(得分:0)

std::array是一种聚合类型;它没有任何用户定义的构造函数。它的单个数据成员是一个数组,不能在函数或构造函数调用中传递;通过值传递的数组衰减到指向其第一个元素的指针,以及array passed by reference cannot be used to initialize an array data member

这意味着array<T, N>只能由另一个array<T, N>NT类型的{}值的字面序列初始化 - 封闭的清单。

从C ++ 17开始,您将能够使用库函数to_array将对数组的引用转换为std::array

std::array<int, 5>  arr{std::experimental::to_array(*reinterpret_cast<int (*)[5]>(&a))};

正如您在Possible implementation部分所看到的,这是在内部分别初始化每个元素:

return { {a[I]...} };

答案 3 :(得分:0)

来自cpp array参考:

  

数组类是聚合类型,因此没有自定义构造函数。

您应该使用默认初始化构建它,然后将矢量内容复制到它。