简体   繁体   English

不同大小的数组数组

[英]array of arrays of different size

I've some code that produces a set of tr1::array of different sizes, but same type, like 我有一些代码生成一组不同大小的tr1 :: array,但类型相同

array<int, 2>
array<int, 4>
array<int, 6>

The number of these arrays, and their sizes, are given in compile time, so I know exactly how many of them there will be and how's big each one (but they may be different). 这些数组的数量及其大小在编译时给出,因此我确切地知道它们中有多少以及每个数组的大小(但它们可能不同)。

Problem: I would like to put them in a collection (using array<> would be great), but type must be equal for all the members and this is not the case. 问题:我想把它们放在一个集合中(使用array <>会很棒),但是对于所有成员来说type必须相同,而事实并非如此。

I thought about using boost::variant, but how can specify a variant with a compile-time determined list of types (I'm thinking about an heavy usage of the preprocessor...)? 我想过使用boost :: variant,但是如何使用编译时确定的类型列表来指定变量(我正在考虑预处理器的大量使用......)? What about using boost::any? 那么使用boost :: any呢? Other methods? 其他方法? (Wild pointers?) (狂野指针?)

TIA ~Aki TIA~Aki

Correction: preprocessor is not usable in this case. 更正:在这种情况下,预处理器不可用。

I would use Boost's MPL and Fusion libraries. 我会使用Boost的MPL和Fusion库。 There are two ways of ending up with the type list: generate them, or explicitly define them. 有两种方法可以结束类型列表:生成它们,或者明确定义它们。 The former is bit more flexible, but it's hard to say which is right for you since we don't know how you get the values you have. 前者有点灵活,但很难说哪个适合你,因为我们不知道你如何获得你拥有的价值。

In any case, generating: 在任何情况下,生成:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
#include <array>
#include <iostream>

namespace bmpl = boost::mpl;

// turns an index into an array
template <typename T>
struct make_array
{
    // or whatever scheme you have
    static const std::size_t size = T::value * 2;

    // define generated type
    typedef std::array<int, size> type;
};

// list of values to convert
typedef bmpl::range_c<size_t, 1, 10> array_range;

// transform that list into arrays, into a vector
typedef bmpl::transform<array_range, make_array<bmpl::_1>,
                            bmpl::back_inserter<bmpl::vector<>>
                                >::type array_collection;

Or explicitly stating: 或者明确说明:

#include <boost/mpl/vector.hpp>
#include <array>
#include <iostream>

namespace bmpl = boost::mpl;

// list all array types
typedef bmpl::vector<
            std::array<int, 2>,
            std::array<int, 4>,
            std::array<int, 6>,
            std::array<int, 8>,
            std::array<int, 10>,
            std::array<int, 12>,
            std::array<int, 14>,
            std::array<int, 16>,
            std::array<int, 18>
                > array_collection;

Either way, you can then use it like this: 无论哪种方式,您都可以像这样使用它:

#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/mpl/for_each.hpp>
#include <typeinfo>

// fusion "fuses" the bridge between MPL and runtime
namespace bf = boost::fusion;

struct print_type
{
    template <typename T>
    void operator()(const T&) const
    {
        std::cout << typeid(T).name() << "\n";
    }
};

struct print_values
{
    template <typename T>
    void operator()(const T& pArray) const
    {
        std::cout << "Printing array with size "
                    << pArray.size() << ":\n";
        std::for_each(pArray.begin(), pArray.end(),
                [](int pX)
                {
                    std::cout << pX <<  " ";
                });
        std::cout << std::endl;
    }
};

int main(void)
{
    // print all the types you have
    bmpl::for_each<array_collection>(print_type());
    std::cout.flush();

    // make a usable type out of the typelist
    typedef bf::result_of::as_vector<array_collection>::type array_fusion;
    array_fusion arrays; // now have an array of different arrays,
                         // compile-time generated but run-time usable

    // access like this:
    bf::at_c<0>(arrays)[1] = 5; 
    bf::at_c<1>(arrays)[2] = 7; 
    bf::at_c<2>(arrays)[0] = 135; 

    // for_each:
    bf::for_each(arrays, print_values());
}

The only way you can put classes of different types in a STL container is if the container contains pointers (references don't work because they are not default constructable) to some base type and the objects you want to collect all inherit from that type. 在STL容器中放置不同类型的类的唯一方法是,如果容器包含指针(引用不起作用,因为它们不是可默认构造的)到某些基类型,并且要收集的对象都从该类型继承。 Note that a container (or any template class) of a type which inherits from a base class does not inherit from a container of the base type. 请注意,从基类继承的类型的容器(或任何模板类)不会从基类型的容器继承。 You could just use void* but you need to do a lot of ugly and dangerous casting and you have to remember to free the memory yourself. 你可以使用void *但你需要做很多丑陋和危险的演员,你必须记住自己释放记忆。 Why don't you write a fixed size array class that allow you to set the size in the constructor? 为什么不编写一个固定大小的数组类,允许您在构造函数中设置大小? if you write as wrapper around araray it should not be too much work. 如果你写一个包装在araray周围,它不应该是太多的工作。 If you want to use some solution based on smart pointers don't be tempted to use auto_ptr as the copy semantics are wrong for STL containers - go for something like the boost shared_ptr. 如果你想使用一些基于智能指针的解决方案,不要试图使用auto_ptr,因为STL容器的复制语义是错误的 - 去像boost shared_ptr这样的东西。

You don't say why you want a collection of statically sized arrays of different sizes. 你没有说为什么你想要一个不同大小的静态大小的数组的集合。 This is rather odd. 这很奇怪。 Why not use a collection of dynamically sized arrays? 为什么不使用动态大小的数组集合?

Your choices are: 你的选择是:

  • use std::vector instead of std::tr1::array. 使用std :: vector而不是std :: tr1 :: array。

  • Store a pointer to the array and the size of the array in your collection. 存储指向数组的指针以及集合中数组的大小。 This could look something like: std::vector<std::pair<int *, size_t> > . 这看起来像: std::vector<std::pair<int *, size_t> > Just make sure that the lifetime of the arrays is at least as long as the lifetime of the vector! 只需确保数组的生命周期至少与向量的生命周期一样长!

  • I would expect boost::variant to work as well, but it would be rather fiddly to use in practice. 我希望boost :: variant能够正常工作,但在实践中使用它会相当繁琐。

boost::variant<array<int, 2>, array<int, 4>, array<int, 6>, ... >

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM