在现代 C++ 中将 std::array<std::array<T,N>> 转换为 std::vector<T>

Posted

技术标签:

【中文标题】在现代 C++ 中将 std::array<std::array<T,N>> 转换为 std::vector<T>【英文标题】:Convert std::array<std::array<T,N>> into std::vector<T> in modern C++ 【发布时间】:2019-09-07 11:44:35 【问题描述】:

我有一堆由 3d 向量 (std::vector&lt;Vector3&gt;) 和索引组成的向量表示的三角形,用以下方式表示

using int3 = std::array<int, 3>;
std::vector<int3> indices;

我需要将indices 转换为std::vector&lt;size_t&gt; 格式才能与库进行交互。

我知道如何使用原始循环来做到这一点,但我想在这里了解如何使用算法来做到这一点。我尝试了类似的东西

std::vector<size_t> indices_converted;
std::transform(std::begin(indices), std::end(indices), std::back_inserter(indices_converted), [](const auto &v) 
);

但这还不够,因为我不能一次将三个值插入到indices_converted 向量中。

那么,你的想法是什么?

【问题讨论】:

使用伪语言,解释您希望如何从三个整数变为单个 size_t。或发布您的“原始循环”示例。 您需要有一个显式循环来将所有元素一一添加。好消息是,由于已知大小,您可以reserve storage,因此不必调整矢量大小。 【参考方案1】:

使用最新版range-v3库的单行:

#include <array>
#include <vector>

#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>

// ...

std::vector<std::array<int, 3>> v = 1, 2, 3, 4, 5, 6, 7, 8, 9;
const auto result = ranges::views::join(v) | ranges::to<std::vector>();

On godbolt

【讨论】:

请注意,这个范围库是为 c++20 标准化的 这是一个非常有趣的方法!它是如何工作的?连接函数是否从一个范围跳转到下一个范围,从一个范围的末尾跳转到下一个范围的开头? 我预计 join 会懒惰地工作,并且性能与将所有内容插入向量的手动循环相当。快速基准测试表明,我上面的 sn-p 甚至比初始调用 reserve 的手动循环更好。太棒了。 @Grisha 你知道是否可以用to&lt;std::array&gt; 替换to&lt;std::vector&gt; 吗? @M.Mac 好像ranges::to还不支持std::array。与std::copy 近似:const auto joined_view = ranges::views::join(v); std::array&lt;int, 9&gt; a; std::copy(begin(joined_view), begin(end), a.begin());【参考方案2】:

您可以使用基于范围的 for 循环或标准算法 std::for_each

例如

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

int main() 

    using int3 = std::array<int, 3>;
    std::vector<int3> indices = 
    
         1, 2, 3 ,  4, 5, 6 ,  7, 8, 9 
    ;

    std::vector<size_t> indices_converted;
    indices_converted.reserve( 3 * indices.size() );

    for ( const auto &item : indices )
    
        indices_converted.insert( std::end( indices_converted ), std::begin( item ), std::end( item ) );
    

    for ( const auto &item : indices_converted ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;

#include <iostream>
#include <array>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 

    using int3 = std::array<int, 3>;
    std::vector<int3> indices = 
    
         1, 2, 3 ,  4, 5, 6 ,  7, 8, 9 
    ;

    std::vector<size_t> indices_converted;
    indices_converted.reserve( 3 * indices.size() );

    std::for_each( std::begin( indices ), std::end( indices ),
                   [&indices_converted]( const auto &item )
                   
                    indices_converted.insert( std::end( indices_converted ), std::begin( item ), std::end( item ) );        
                    );

    for ( const auto &item : indices_converted ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;

在这两种情况下,输出都是

1 2 3 4 5 6 7 8 9 

【讨论】:

以上是关于在现代 C++ 中将 std::array<std::array<T,N>> 转换为 std::vector<T>的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL应用与实现5: 如何使用std::array (since C++11)

C++ std::array 到 shared_ptr 的向量

数组的 C++ 向量

C++ 静态多数组包装器

在 C++11 中具有对齐元素的 std::array 类型

std::array<T, ?> 类型的成员变量