开发者

C++ as in Java?: vector of vectors with *variable* length of int

开发者 https://www.devze.com 2022-12-12 03:04 出处:网络
My model would best use some v int[30][i][N_i]; structure that is 30 vectors of tuples of ints, where v[0] is a dummy,

My model would best use some

v int[30][i][N_i];

structure that is 30 vectors of tuples of ints, where

v[0] is a dummy,

v[1] are plain ints (N_0 of them),

v[2] are pairs of int (N_1 pairs)

...

v[29] would be 29-tuples of int (N_29 of them)

This is not vector<vector<int>> like in "generic-vector-of-开发者_运维知识库vectors-in-c"

Apparently, the outer fixed dim=30 is no problem, the inner one is taken care of by the self-extending STL vector class.

Is there any way to get the middle dimension fixed, but not constant?


As I wrote in a comment to your question, I'm not sure to understand what you are looking for (and I'm very interested by the "as in Java" part, BTW).

But since I thought it would be fun to see how it could be generated with Boost.MPL (and Fusion... and Array), I'm assuming that you want a statically defined structure whose Ntn element is a vector of int arrays of size N:

#define FUSION_MAX_VECTOR_SIZE 30

#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/inserter.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/size_t.hpp>

#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/as_vector.hpp>

#include <boost/array.hpp>

#include <vector>


namespace bf = boost::fusion;
namespace bmpl = boost::mpl;

// Type generator used for elements 2..N
// For those elements, the type of the n'th element is
// std::vector<boost::array<int, n>>
template<class SizeT>
struct VectorOfArray
{
    typedef std::vector<boost::array<int, SizeT::type::value> > type;
};

// The dummy type used for the first element
struct Dummy{};

// The container itself
template<size_t Size>
struct StrangeContainer
{

    // Define a fusion::vector (this is, more or less, equivalent to a tuple)
    // of "Size" elements, where:
    // - the type of element 0 is Dummy, 
    // - the type of element 1 is vector<int>
    // - the type of the n'th element is vector<array<int, n>>
    typedef typename bf::result_of::as_vector<
        typename bmpl::transform<
            bmpl::range_c<size_t, 2, Size>,
            VectorOfArray<bmpl::_1>,
            bmpl::back_inserter<
                bmpl::vector<Dummy, std::vector<int> >
            >
        >::type
    >::type ContentsType;

    // Helper struct to compute the return type of the "At()" member
    template<size_t I>
    struct ElemType
    {
        typedef typename VectorOfArray<bmpl::size_t<I> >::type type;
    };

    // Specialize "At()"'s return type for element 1
    template<>
    struct ElemType<static_cast<size_t>(1)>
    {
        typedef std::vector<int> type;
    };

    // Specialize "At()"'s return type for element 0
    template<>
    struct ElemType<static_cast<size_t>(0)>
    {
        typedef Dummy type;
    };

    // Get the I'th element
    template<size_t I>
    typename ElemType<I>::type& 
    At()
    {
        return bf::at_c<I>(m_Contents);
    }

    // The fusion vector holding the elements
    ContentsType m_Contents;
};

int main()
{
    StrangeContainer<30> s;
    Dummy& d = s.At<0>();
    s.At<1>().push_back(1);
    s.At<2>().push_back(boost::array<int, 2>());
    s.At<3>().push_back(boost::array<int, 3>());
    s.At<29>().push_back(boost::array<int, 29>());
    s.At<29>()[0][0] = 1234;

    return 0;
}


The best way to do what you want is write wrapper functions around the vector accessors. The best way to wrap existing behavior is to write a new class that is implemented with your fancy vector of vector of what ever.


I'm Michael (the initial author) now having ID La-AIDA

Firstly, thank you all, Boost & Fusion where new to me.

To Éric: One Typo: v[1] should have N_1 entries, v[2] N_2 and so forth. I would like STL-like stuff, not C-arrays (lacking bounds check with no option to add it).

New comment to Éric: I tried your solution, it worked (almost, after removing the dummy query) immediately! Thank you! But: I need something like

 for (i = 1;i < 30;i++) {
    cout << s.At<i>[0] << endl; 
 }

that is, the index for At<..> should be variable (that is the whole point, to be able to run an index instead of treating 30 hard-coded things separately)
but gcc complains with error: 'i' cannot appear in a constant-expression

About the "as in Java": AfaIk, a two-dim matrix in Java is not some int v[10][10]; with fixed dimensions, but something like int[][] v; where you first have a

v = new int[10][];

(or similar syntax) and then, and this is the point:

v[0] = new int[1];
...
v[9] = new a[10];

which makes a triangular matrix, or of course any form you like. In fact a regular 10-by-10 matrix as well requires 1 plus 10 new's.

About the structure itself: An equivalent data structure would be

vector<int> v1;
vector<pair<int,int>> v2;
vector<int,int,int> v3;
...
vector<int[29]> v29;

where however we would have to address each of the 30 parts separately.

I would like to be able to say v[5][3][123] = 99; to set the 3rd component in the 123rd 5-tuple to 99, without defining

vector<int> v[30][30];

which would do the trick, but wasting enormous space, since v[1][2..30][0..\infty] or more generally v[i][i+1..30][*] are never used.

So, in my problem, I have a list of int's , another of pairs, of triples,..., of 30-tuples of int's, which all should be sortable etc., within a single structure, without wasting space.

0

精彩评论

暂无评论...
验证码 换一张
取 消