1

I've wanted a wrapper around arrays, such, it would be stored at the stack - to be not concerned about memory releasing - be initializable via brace lists, and possibly be substitutable in any place of an ordinary array. Then, I've produced the following code. And now am wondering, have I missed something. -- So - is it what I've wanted?

template<class T, size_t size>
struct Array
{
    T body[size];

    operator T* () { return body; }
};

Edit:

I might be imprecise. The wrapper is only for constructional purpose. It shall be used for constructing arrays from brace lists, when being in an initialization list (primarily). Like

class A {
    protected: A(int array[])
    ...

class B : public A {
    public: B() : 
        A( (Array<int, 2>) {{ 1, 2 }} )
        ...

There was a proposition of a const version of the casting operator. - I've been considering this, but am not sure, is it really needed. While casting to const T[] is done implicitly through the existing operator, and a constant array can be defined by giving T = const ..., is there still a reason?

3
  • 21
    You've just described std::array Commented May 12, 2013 at 21:42
  • Your class should also provide const/non-const overloads of operator[N]. Commented May 12, 2013 at 21:46
  • @0x499602D2 [] should already be handled by the conversion to pointer, but good point about an additional const version of that conversion operator. Commented May 12, 2013 at 21:48

1 Answer 1

6

For a basic example, I don't think there's much you can improve on, except for a few helper functions. In particular, it would be nice to have a method that returns the size:

constexpr std::size_t size() const { return size; }

In addition, here are a few others:

  • const/non-const overloads of operator[N]:

    As @ChristianRau stated in the comments, a operator T* provides a non-const version. We can implement the const version as such:

    T const& operator [](std::size_t n) const
    {
        return body[n];
    }
    // similarly for non-const:
    T& operator [](std::size_t n) { return body[n]; }
    
  • begin() and end() sequencers (very useful e.g. for the C++11 range-based for):

    T* begin() { return body; }
    T* end()   { return body + size; }
    
    // const versions... very much the same
    T const* cbegin() const { return body; }
    T const* cend()   const { return body + size; }
    T const* begin()  const { return cbegin(); }
    T const* end()    const { return cend(); }
    
  • an at() method, which includes bounds checking (as opposed to operator[] by convention):

    T const& at(std::size_t offset) const
    {
        // You should do bounds checking here
        return body[offset];
    }
    // also a non-const version again..
    
  • It would also be nice to have a constructor that takes an std::initializer_list<T> so that you don't have to use the aggregate-initialization:

    #include <algorithm>
    #include <initializer_list>
    
    template <typename T, std::size_t N>
    struct Array
    {
        ...
        Array(std::initializer_list<T> const& list)
        {
            std::copy(list.begin(), list.end(), body);
        }
        ...
    };
    

    Here is another one suggested by @DyP (initializer list always copies, perfect forwarding tries to avoid that):

    template <typename T, std::size_t N>
    struct Array
    {
        ...
        template <typename... Args>
        // possibly constexpr
        Array(Args&&... args) : body{ std::forward<Args>(args)... } 
        {}
        ...
    };
    

Here is the program in action if you want to see it -- http://ideone.com/Zs27it#view_edit_box

There are others features you can include, but as I said this is a basic example, and you would most likely be better off using something like std::array which has more or less the same methods.

Sign up to request clarification or add additional context in comments.

12 Comments

I think your second comment makes a better answer. The question does describe the desired features.
Well, maybe I used too big word. The wrapper is not a substitute of array, but a tool purposed purely for construction. - Feathers aren't needed. :)
Maybe you want return a T const& from a at(std::size_t) const?
IMO a ctor with template parameter pack could be better since it can use perfect forwarding (and be constexpr).
What I don't understand also with std::array is why size is not a static member function.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.