By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,778 Members | 1,997 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,778 IT Pros & Developers. It's quick & easy.

inhomogeneous container

P: n/a
Hi,

I have an array class (the blitz library actually) which looks like this:

template<typename P_numtype, int N_rank>
class Array : public MemoryBlockReference<P_numtype>
, public ETBase<Array<P_numtype,N_rank> >
{
// ... code
};
I would like to create a container class which allows me to store
Array<T,N> objects of different rank N and same data type T. The
container should have [](int i) operators which would return a reference
at i-th array.
My questions would be how could I deduce the returned type of the
operator [](int) and what should I use to store the arrays ?

template<class T_numtype>
class ArrayPool{

public:

Array<T_numtype, N_rank ??? > operator[](int i)
{
// ... return i-th array from pool
}

private:
// ... data

};
Thanks in advance.
Jun 22 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Valeriu Catina wrote:
Hi,

I have an array class (the blitz library actually) which looks like this:

template<typename P_numtype, int N_rank>
class Array : public MemoryBlockReference<P_numtype>
, public ETBase<Array<P_numtype,N_rank> >
{
// ... code
};
I would like to create a container class which allows me to store
Array<T,N> objects of different rank N and same data type T. The
container should have [](int i) operators which would return a reference
at i-th array.
My questions would be how could I deduce the returned type of the
operator [](int) and what should I use to store the arrays ?

template<class T_numtype>
class ArrayPool{

public:

Array<T_numtype, N_rank ??? > operator[](int i)
{
// ... return i-th array from pool
}

private:
// ... data

};
Thanks in advance.


Obviously there is no sensible return for operator[] as you've defined
it. Assuming you cannot modify the Array class, probably your best
option is to return a type that exposes the interface of Array<T, N>,
but does not have any template parameters itself, and allows you to
query for N. This requires several stages of indirection, which I will
now describe:

1) Create a class that exposes the same interface as Array<T, N> (and
anything else you'd want to do, such as querying rank), but consists of
only pure virtual functions. This class will also need a "clone"
function, for reasons that will become apparent. In the example code
below this is called ArrayTImplBase.

2) Create a class template (on T and N) that has data member of type
Array<T, N> and inherits from the class created in step 1. This class
should implement the inherited virtual functions by forwarding them to
the data member. In the example code this is called ArrayTImpl.

3) Create a class that exposes the same interface as that in step 1, and
can be constructed from an instance of Array<T, N> (i.e., the
constructor is templated, not the class). This class will use the PIMPL
idiom to manage an object of type ArrayTImpl<T, N> (and therefore an
object of type Array<T, N>). If you want to store these in a standard
container (which was the whole point), then you MUST implement a copy
constructor and operator=. This is why it was necessary to create a
clone function. In the example code this is called ArrayT.
While I haven't done exhaustive testing, I think the following
represents a minimal working example:
#include <cstddef> // for std::size_t
#include <algorithm> // for std::swap

template <typename T, std::size_t N>
class Array
{
public:
int f1()
{
return 1 ;
}

int f2()
{
return 2 ;
}

int f3()
{
return 3 ;
}
} ;

class ArrayTImplBase
{
public:
virtual std::size_t rank() const = 0 ;
virtual ArrayTImplBase * clone() = 0 ;
virtual ~ArrayTImplBase()
{}

virtual int f1() = 0 ;
virtual int f2() = 0 ;
virtual int f3() = 0 ;
} ;

template <typename T, std::size_t N>
class ArrayTImpl : public ArrayTImplBase
{
public:
std::size_t rank() const
{
return N ;
}

ArrayTImpl<T, N> * clone()
{
return new ArrayTImpl(array_) ;
}

ArrayTImpl(const Array<T, N> & array)
: array_(array)
{}

int f1()
{
return array_.f1() ;
}

int f2()
{
return array_.f2() ;
}

int f3()
{
return array_.f3() ;
}

private:
Array<T, N> array_ ;
} ;

template <typename T>
class ArrayT
{
public:

template <std::size_t N>
explicit ArrayT(const Array<T, N> & array)
: pimpl_(new ArrayTImpl<T, N>(array))
{}

ArrayT(const ArrayT & a)
: pimpl_(a.pimpl_->clone())
{}

ArrayT & operator=(const ArrayT & a)
{
ArrayTImplBase * p = a.pimpl_->clone() ;
std::swap(p, pimpl_) ;
delete p ;
}

~ArrayT()
{
delete pimpl_ ;
}

std::size_t rank() const
{
return pimpl_->rank() ;
}

int f1()
{
return pimpl_->f1() ;
}

int f2()
{
return pimpl_->f2() ;
}

int f3()
{
return pimpl_->f3() ;
}

private:

ArrayTImplBase * pimpl_ ;
} ;
--
Alan Johnson
Jun 22 '06 #2

P: n/a
Alan Johnson wrote:
While I haven't done exhaustive testing, I think the following
represents a minimal working example:

[lots of code removed]

One minor correction. ArrayT's operator= should end with "return *this ;".

Also, a usage example:

#include <vector>

int main()
{
std::vector< ArrayT<int> > v ;

v.push_back(ArrayT<int>(Array<int, 5>())) ;
v.push_back(ArrayT<int>(Array<int, 100>())) ;
v.push_back(ArrayT<int>(Array<int, 20>())) ;

v[0].f1() ;
v[0].f2() ;
v[0].f3() ;
// Do whatever.
}

--
Alan Johnson
Jun 22 '06 #3

P: n/a
Alan Johnson wrote:
Alan Johnson wrote:
While I haven't done exhaustive testing, I think the following
represents a minimal working example:

[lots of code removed]

One minor correction. ArrayT's operator= should end with "return *this ;".

Also, a usage example:

#include <vector>

int main()
{
std::vector< ArrayT<int> > v ;

v.push_back(ArrayT<int>(Array<int, 5>())) ;
v.push_back(ArrayT<int>(Array<int, 100>())) ;
v.push_back(ArrayT<int>(Array<int, 20>())) ;

v[0].f1() ;
v[0].f2() ;
v[0].f3() ;
// Do whatever.
}


Thanks for your hints,

actually I have some functions whose arguments are arrays of different rank:

void some_func(Array<double,4>& A, Array<double,4>& B,
Array<double,3>& C, Array<double,2>& D, Array<double,2>& E);

I just don't like functions with many arguments and my initial idea was
to create an array container and to pass it as argument to my functions.

So far I cannot think of a more elegant way to write these functions and
ellipsis are out of question.

Any other suggestion is welcome.

Bye,

V. Catina.


Jun 23 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.