2013-06-25 62 views
1

我想创建这样的结构:C++ 11返回一个std ::阵列具有不同尺寸

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*吗?

+8

erm,返回一个'std :: vector <>'? – Nim

+0

我忘了&。我必须有能力修改这个数组。 – Dejwi

+0

您可以返回对矢量的引用,并将其修改为您的心灵内容... – Nim

回答

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; 
+0

OP在'switch' /'case'语句中具有编译时间常量 - '1'到'50'。问题不在于缺少编译时间常量,而是编译时间常量*在函数体外*。 – Yakk

+0

当然,但我有点解释原来的帖子,意思是参数'x'可以期望编译时常量,无论函数被调用。 – Saran

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>通过N-1适用0Contents并产生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; 

这是50std::tuple不同std::vector S,其中每个存储1一个std::array通过50byte秒。

这花费的时间远远少于50行,虽然这很难让它工作并理解它,但这意味着代码是一致的并且只生成一次:一条特定行的机会要少得多错误的,以及一次性错误的可能性要高得多。您可以使用编译时间值通过std::get<7>(my_tuple)提取第n个元素。哦,如果你想要10010而不是50?改变一个常量。

接着,contiguous_range结构,基本上是一打扮对指针给你一个类型擦除的方式来看待N元件的阵列(或其它缓冲剂),像Passing a std::array of unknown size to a function

现在,则可以手动编写你的大开关语句,或者你可以建立一个函数指针表,提取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 /粘贴,每次更改一个单一的数字,其中一个有一个轻微的错字,会产生一个微妙的fenceposting错误,只发生在一个晦涩难懂仅在发布模式下重现测试用例。