C ++ 11返回一个不同大小的std :: array

时间:2013-06-25 07:40:02

标签: templates c++11 stdarray

我想创建这样一个结构:

struct Arrays{
    typedef unsigned char byte_t;

    std::array<byte_t, X>& get(int x, int y)
    {
        switch(x){
            case 1: return arr_1.at(y);
            case 2: return arr_2.at(y);
            ... up to ...
            case 50: return arr_50.at(y);
            default: break;
        }
    }

    std::vector<std::array<byte_t, 1>> arr_1;
    std::vector<std::array<byte_t, 2>> arr_2;
    ... up to ....
    std::vector<std::array<byte_t, 50>> arr_50;
};

我知道

std::array<byte_t, 1>

std::array<byte_t, 2>

是不同的结构,所以这是不可能的。我怎样才能以不同的方式管理它?我是否必须从方法中返回byte_t*

2 个答案:

答案 0 :(得分:2)

正如之前的评论所说,数组大小是编译时常量。实现此目的的唯一方法是将x作为模板参数传递。以下怎么样? (为方便起见,我已经定义了一个类vector_of_arrays来保存你的向量arr_1arr_50,这样我就可以通过数字来引用每个向量而不必切换和给出一个名字)

#include <array>
#include <type_traits>
#include <vector>

template <typename type, size_t max_size>
class vector_of_arrays : public std::vector<std::array<type, max_size>>
{
private:
    vector_of_arrays<type, max_size - 1> _next;

public:
    template <size_t size>
    typename std::enable_if<(size < max_size), vector_of_arrays<type, size>&>::type
    get_vector_for_size()
    {
        return _next.get_vector_for_size<size>();
    }

    template <size_t size>
    typename std::enable_if<(size == max_size), vector_of_arrays<type, size>&>::type
    get_vector_for_size()
    {
        return *this;
    }
};

template <typename type>
class vector_of_arrays<type, 1> : public std::vector<std::array<type, 1>>
{
public:
    template <size_t size>
    typename std::enable_if<(size == 1), vector_of_arrays<type, size>&>::type
    get_vector_for_size()
    {
        return *this;
    }
};

struct arrays
{
    typedef unsigned char byte_t;
    vector_of_arrays<byte_t, 50> va;

    template <size_t x>
    std::array<byte_t, x>& emplace_array()
    {
        va.get_vector_for_size<x>().emplace_back();
        return *(va.get_vector_for_size<x>().end() - 1);
    }

    template <size_t x>
    std::array<byte_t, x>& get(int y)
    {
        return va.get_vector_for_size<x>().at(y);
    }
};

要测试此代码,您可以执行类似

的操作
arrays foo;
auto& arr1 = foo.emplace_array<3>();
arr1[0] = 1.;
arr1[1] = 2.;
arr1[2] = 3.;

auto& arr2 = foo.get<3>(0);
std::cout << arr2[0] << ' ' << arr2[1] << ' ' << arr2[2] << std::endl;

答案 1 :(得分:1)

首先,你违反了DRY。

替换它:

std::vector<std::array<byte_t, 1>> arr_1;
std::vector<std::array<byte_t, 2>> arr_2;
... up to ....
std::vector<std::array<byte_t, 50>> arr_50;

有类似的东西:

template<typename Pack, unsigned X> struct append;
template<template<unsigned...>class Pack, unsigned... Xs, unsigned X>
struct append<Pack<Xs...>, X> {
  typedef Pack<Xs..., X> type;
};
template<typename Pack, unsigned X> using Append=typename append<Pack,X>::type;


template<unsigned N, template<unsigned>class Contents>
struct auto_tuple {
  typedef Append< typename auto_tuple<N-1, Contents>::type, Contents<N-1> > type;
};
template<template<unsigned>class Contents>
struct auto_tuple<0, Contents> {
  typedef std::tuple<> type;
};
template<unsigned N, template<unsigned>class Contents>
using AutoTuple = typename auto_tuple<N,Contents>::type;

其中AutoTuple<N, Contents>0通过N-1应用于Contents,并从中生成std::tuple。写:

template<typename T, unsigned N>
using vec_of_array = std::vector<std::array<T, N>>;
template<unsigned N>
using vec_of_byte_array = vec_of_array<byte_t, N>;
template<unsigned N>
using get_nth_byte_array = vec_of_byte_array<N+1>;

用于填充tuple之类的内容:

typedef AutoTuple<50, get_nth_byte_array> my_tuple;

std::tuple 50std::vectorstd::array,每个1 50 byte50 {{1} }}第

这比std::get<7>(my_tuple)行要少得多,虽然这很难让它工作并理解它,但这意味着代码是统一的并且生成一次:一个机会的可能性要小得多特定的行是错误的,一次出现错误的可能性要大得多。您可以使用编译时值通过100提取第n个元素。哦,如果你想要1050而不是contiguous_range?改变一个常数。

接下来,基本上是一对装扮指针的N结构为您提供了一种类型擦除的方式来查看contiguous_range元素的数组(或其他缓冲区),如{{3 }}

现在,您可以手动编写big switch语句,也可以构建一个函数指针表来提取// DataStorage is the tuple of std::vector of std::array template<unsigned...> struct seq{}; template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {}; template<unsigned... s> struct make_seq<0,s...>:seq<s...> {}; template<unsigned N> struct get_array { static contig_range<byte> get(DataStorage& data, unsinged idx) { return ( std::get<N>( std::forward<Data>(data) )[idx]; } }; 并自动构建它。

N

并构建一个包含50个数组的数组(每个数组都有不同的typedef contig_range<byte> (*array_getter)( DataStorage&, unsigned idx ); template<unsigned N, unsigned... S> std::array< array_getter, N > populate_array_helper( seq<S...> ) { return { get_array<S>::get... }; } template<unsigned N> std::array< array_getter, N > populate_array() { return populate_array_helper( make_seq<N>() ); } )存储在以下数组中:

byte

然后您可以使用运行时参数进行查找,调用它,并获得连续数组{{1}}的类型擦除实例。

非代码开销是50个指针(用于查找表),3个指针(用于包含向量)。

你永远不会做相同代码的cpoy /粘贴50次,每次更改一个数字,其中一个有一个轻微的拼写错误,产生一个微妙的fenceposting错误,只发生在一个不明显的,难以仅在发布模式下重现测试用例。