1

我想创建这样一个结构:

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*从方法返回吗?

4

2 回答 2

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;
于 2013-06-25T08:12:07.217 回答
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;

whereAutoTuple<N, Contents>适用于并从中0生成一个。写:N-1Contentsstd::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的s ,每个存储一个到s。50std::vectorstd::array150 byte

这比行少得多50,虽然这将更难让它工作和理解它,但这意味着代码是统一的并且生成一次:一个特定的行错误的可能性要小得多,而且远一次所有事情都出错的可能性更高。您可以使用编译时值通过std::get<7>(my_tuple). 哦,如果你想要10010代替50?改变一个常数。

接下来,contiguous_range基本上是一对指针的结构为您提供了一种类型擦除的方式来查看N元素的数组(或其他缓冲区),例如将未知大小的 std::array 传递给函数

现在,您可以手动编写大 switch 语句,也可以构建一个函数指针表来提取contiguous_range并自动构建它。

// 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];
  }
};

并构建一个由 50 个数组组成的数组(每个数组都有一个不同的N),存储在一个数组中:

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.

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

而且您永远不会对相同的代码进行 50 次 cpoy/paste 并且每次都更改一个数字,其中一个有轻微的拼写错误,会产生一个微妙的栅栏错误,该错误仅发生在一个晦涩难懂的、难以重现的测试用例中仅在发布模式下。

于 2013-06-25T14:08:18.597 回答