массив массивов разного размера - PullRequest
4 голосов
/ 28 июля 2010

У меня есть некоторый код, который производит набор tr1 :: array разных размеров, но одного типа, например

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

Число этих массивов и их размеры, даются во время компиляции, поэтому я точно знаю, сколько их будет и сколько у каждого (но они могут быть разными).

Проблема: я бы хотел поместить их в коллекцию (используямассив <> (было бы здорово), но тип должен быть одинаковым для всех членов, и это не так.

Я думал об использовании boost :: variable, но как можно указать вариант во время компиляции?определенный список типов (я имею в виду интенсивное использование препроцессора ...)?Как насчет использования boost :: any?Другие методы?(Дикие указатели?)

TIA ~ Aki

Исправление: препроцессор в этом случае не используется.

Ответы [ 3 ]

3 голосов
/ 28 июля 2010

Я бы использовал библиотеки Boost MPL и Fusion.Есть два способа получить список типов: сгенерировать их или явно определить.Первый вариант более гибкий, но трудно сказать, какой из них подходит вам, поскольку мы не знаем, как вы получаете значения, которые у вас есть.

В любом случае, генерируется:

#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;

Или явно указав:

#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;

В любом случае, вы можете использовать его так:

#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());
}
0 голосов
/ 28 июля 2010

Вы не говорите, зачем вам коллекция статических размеров разных размеров.Это довольно странно.Почему бы не использовать коллекцию динамически изменяемых массивов?

Вы можете выбрать:

  • использовать std :: vector вместо std :: tr1 :: array.

  • Сохраните указатель на массив и размер массива в вашей коллекции.Это может выглядеть примерно так: std::vector<std::pair<int *, size_t> >.Просто убедитесь, что время жизни массивов не меньше, чем время жизни вектора!

  • Я бы ожидал, что Boost :: Вариант также будет работать, но это было бы скорееиспользовать на практике.

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

0 голосов
/ 28 июля 2010

Единственный способ поместить классы разных типов в контейнер STL - это, если контейнер содержит указатели (ссылки не работают, потому что они не конструируются по умолчанию) на некоторый базовый тип, а все объекты, которые вы хотите собрать, наследуются отэтот тип.Обратите внимание, что контейнер (или любой шаблонный класс) типа, который наследуется от базового класса, не наследуется от контейнера базового типа.Вы можете просто использовать void *, но вам нужно делать много уродливых и опасных кастований, и вы должны помнить, чтобы освободить память самостоятельно.Почему бы вам не написать класс массива фиксированного размера, который позволит вам установить размер в конструкторе?если вы пишете как обертку вокруг araray, это не должно быть слишком много работы.Если вы хотите использовать какое-либо решение, основанное на умных указателях, не поддавайтесь искушению использовать auto_ptr, так как семантика копирования не подходит для контейнеров STL - используйте что-то вроде boost shared_ptr.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...