2010-07-28 6 views
4

Я код, который производит набор tr1 :: массив разных размеров, но тот же тип, какмассив массивов разного размера

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

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

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

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

ТИА ~ Aki

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

+0

'станд :: вектор 'вероятно, будет проще всего. Просто не меняйте размер. :) По общему признанию, это не совсем то же самое, но это чисто. – GManNickG

+0

Да, ну, у меня уже есть реализация, которая использует std :: vector вместо tr1 :: array, но использование динамического размера бессмысленно, поскольку они могут вычисляться во время компиляции, поэтому я искал статическое решение. – AkiRoss

+0

вам может понравиться один из этих контейнеров: http://www.boost.org/doc/libs/1_43_0/libs/fusion/doc/html/fusion/container.html. также, если вы хотите ответить кому-нибудь, используйте @, как это @aaa – Anycorn

ответ

3

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

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

#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

MPL кажется решением :) Спасибо. – AkiRoss

+0

Я всегда рад видеть сообщения об использовании некоторых имхо «продвинутых» (или, может быть, просто «новых») библиотек повышения, таких как mpl/fusion/proto/phoenix. Когда-то я видел больше сообщений о больших вариантах использования (есть даже некоторые вопросы об этом, но не много ответов). Но спасибо за ваш пример! – sascha

0

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

0

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

Ваш выбор:

  • использование станд :: вектор вместо станд :: tr1 :: массив.

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

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

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

Смежные вопросы