1

I have a bunch of structs like:

struct A { ... }
struct B { ... }
struct C { ... }

I want to devise a function that can accept arrays of these structs and iterate through each element of the array and call another function like:

template <typename T>
ostream& process(ostream& os, const T* array) {
   // output each element of array to os (but how do we know the length?)
}

A a_array[10];
// in practice, this is actually operator<<, so I cannot pass in the
// size explicitly
process(..., a_array);

Update: I cannot use any of the std containers here. It has to be an array unfortunately!

1
  • 3
    Why are you not using std::vector or std::array? Commented Jan 4, 2012 at 17:08

4 Answers 4

10

Array-to-pointer decay is really, really bad.

Fortunately, C++ has array references, which know their size.

template<typename T, size_t N> ostream& process(ostream& os, const T (&arr)[N]) {
    // use N
}
Sign up to request clarification or add additional context in comments.

9 Comments

I've always seen const T (&arr)[N], but I suppose it works the same.
I've no idea, it's been a really long time since I used that syntax.
I think it is advantageous to drop the const. The template will automatically make the type const if it needs to be, but if you pass in a non-const array I seem to recall it won't know how to handle it.
The notation const T(&arr)[Size] definitely works to deduce the size of a statically sized array. Leaving off the const has the advantage that the constness is correctly deduced, e.g. when getting an end iterator for the array.
@Dietmar: Oh noes! Code bloat! My binary, it might consume a couple more KB, compared to my hundreds of MB of art and such.
|
7

You could use a std::vector<T> instead of an simple array.

template <typename T>
ostream& process(ostream& os, const std::vector<T> &array) {
   for(std::vector<T>::const_iterator iterator = array.begin(); iterator != array.end(); ++iterator)
   {
      //...
   }
}

Or you can go the std::array way (If your compiler support it and N is constant).

template <typename T, int N>
ostream& process(ostream& os, const std::array<T, N> &array) {
   for(std::array<T, N>::const_iterator iterator = array.begin(); iterator != array.end(); ++iterator)
   {
      //...
   }
}

// Usage:
array<int, 10> test;
process(..., test);

2 Comments

why not std::array<T, N>? The size is known and constant.
If the compiler doesn't have std::array, boost::array is always an option
2

You need to use the following format for arrays:

template <typename T, size_t N>
void foo(const T (&arr)[N]) {
    ...
}

Otherwise, size information will be lost.

Comments

0

Or, a simple template bounds checked array.

template< typename T, unsigned int Size >
class Array
{
    public:

    T& operator[]( unsigned int index )
    {
       assert( index < Size );
       return mElements[ index ];
    }

    const T& operator[]( unsigned int index ) const
    {
       assert( index < Size );
       return mElements[ index ];
    }

    unsigned int Capacity() const
    {
        return Size;
    }

    private:
        T mElements[ Size ];
};

And then

template< typename T, unsigned int Size >
void Process( Array< T, Size >& array )
{
    for( unsigned int i = 0; i < Size; ++i )
    {
        //use array[i]
    }
}

And to tie it together

Array< int, 10 > array;
Process( array );

It's a bit of a roll your own solution, but it's probably roughly equivalent (although a less functional array class) to std::Array or boost

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.