Boost logo

Boost :

From: Tomasz Kowalczyk (tomek_at_[hidden])
Date: 2000-05-28 10:11:42


Nicolai Josuttis wrote:
>
> Hi Beman, hi all others,
>
> late but hopefully not too late attached here
> is a new version of class array<>.
> [..]
> Comments are welcome.
> Esspecially regarding the initialization stuff.

I will try to add something constructive :)

In the end of this mail, I have included an example of a technique which
can be used to construct array elements with given arguments similarly
to C array, and still be able to pass default value to initialize all
the other elements, similarly to std::vector. This technique uses
placement construction, like most std containers.

Example how the usage may look like:

    // initialize first three elements of "a" explicitly, others to 0
    array<double,5> a = (var | -11, 'a', 56.2);
    // initialize first 4 elements of "b" explicitly, others to 100
    array<int,7> b( (var | 'q', 22UL, 0772, -12), 100 ) ;

The name "var", and choice of operators "|" and "," are just my quick
hack after a few attempts to make it look good. "var" serves as a seed
for the list, and operators just fill that list.

The main drawbacks I can see:

1. Array stores internally char[] and not T[]. However, there is no
guarantee that internally stored char[] is properly aligned to store
objects of type T. Unfortunately, I do not know of any C++ mechanism
which would allow to enforce this and not call T's constructors at the
same time.
2. Initialization function init_array_elements is called recursively.
This can affect performance for many elements.
3. Initialization list (and generally all this example) will not compile
without really good template specialization support.
4. Initialization list structure (named varlist here) does not fit well
into a public interface of an array unless it is separately standarized.

I was able to compile this code with egcs 1.1.2

Tomasz

/////////////////////////////////////////////////////////////////////////

#include <memory>
#include <new>

struct nil;

// A list with variables with varying types.

template <class V, class N = nil>
struct varlist
{
    enum { pos = N::pos + 1 };

    typedef V value_type;
    typedef N next_type;
    
    value_type var;
    next_type next;
    
    varlist( value_type v, const next_type &n )
        : var(v)
        , next(n)
        {}
};

template <class V>
struct varlist<V>
{
    enum { pos = 0 };

    typedef V value_type;
    typedef nil next_type;
    
    value_type var;
    
    varlist( value_type v ) : var(v) {}
};

    

//
// For convenient generation of variable reference lists, the
// following syntax is introduced:
//
// (var | a,b,c)
//
// Creates a list of references for variables c,b,a (in this order).
// The reverse order is enforced by the operator binding.
//

const struct varlist_seed { varlist_seed() {} } var;

template <class A>
varlist<A&> operator | ( const varlist_seed &, A &a ) {
    return varlist<A&>(a);
}

template <class A, class B, class C>
varlist<C&,varlist<A,B> > operator , ( const varlist<A,B> &v, C & c ) {
    return varlist<C&,varlist<A,B> >(c,v);
}

template <class A>
varlist<const A&> operator | ( const varlist_seed &, const A &a ) {
    return varlist<const A&>(a);
}

template <class A, class B, class C>
varlist<const C&,varlist<A,B> > operator , ( const varlist<A,B> &v,
const C & c ) {
    return varlist<const C&,varlist<A,B> >(c,v);
}

// Initialization of array elements from the varlist

namespace detail {
    template <class T, class A, class V>
    void init_array_elements ( T * data, const varlist<A,V> &v ) {
        init_array_elements( data, v.next );
        new (data + varlist<A,V>::pos) T(v.var);
    }
    
    template <class T, class A>
    void init_array_elements ( T * data, const varlist<A,nil> &v ) {
        new (data) T(v.var);
    }
}

// Very limited array class, which is supposed to
// ilustrate array element initialization

template <class T, int N>
class array {
public:

    template <class U, class V>
    array( const varlist<U&,V> &v, const T &def = T() )
    {
        detail::init_array_elements( reinterpret_cast<T*>( data_ ), v );

        std::uninitialized_fill( data() + varlist<U&,V>::pos + 1,
                                 data() + N,
                                 def );
    }

    const T * data() const { return reinterpret_cast<const T*>(data_); }
    T * data() { return reinterpret_cast<T*>(data_); }

    int size() const { return N; }

    const T & operator [] ( int i ) const { return *(data() + i); }
    T & operator [] ( int i ) { return *(data() + i); }

private:
    char data_[ sizeof(T) * N ];
};

// Simple test

#include <iostream>

template <class T, int N>
ostream & operator << ( ostream &os, const array<T,N> &a )
{
    os << "[";
    for (int i = 0; i < N; i++)
        os << " " << a[i];
    os << " ]";
}

main()
{
    array<double,5> a = (var | -11, 'a', 56.2 );
    cout << a << endl; // [ -11 97 56.2 0 0 ]

    array<int,7> b( (var | 'q', 22UL, 0772, -12 ), 100 ) ;
    cout << b << endl; // [ 113 22 506 -12 100 100 100 ]
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk