0

I have a class that contains some standard container that I want to return in a method, like so (just an example):

class IntArray
{
public:
    IntArray(const vector<int>& vals) : vals(vals) {}

    const vector<int>& getValues() const { return vals; }
    vector<int>& getValues() { return vals; }

private:
    vector<int> vals;
};

I returned the vector by reference to avoid making a copy of it (I would rather not want to rely on RVO). I don't want to do it using OutputIterators, because I really want to keep it short with C++11 range-based for loops like so:

for (int val : arr.getValues()) {
    // Something
}

But say I want to change the type of the member variable to list<int>, then I would have to change the method's return type, too, which might lead to incompatibilities. I also don't want to implement begin() and end() methods because there might be more than one such container per class.

What would be the preferred way of doing this?

4
  • All classes supported by std::begin and std::end, or which have a begin and end member functions, will be supported by the ranged-based for loop. Of course this includes all standard containers. Commented Aug 18, 2014 at 5:24
  • Why are you using this wrapper to begin with? Why not just return a sequence<T> where sequence<T> wraps the vector<> or list<> and provides the .begin() and .end() methods? Commented Aug 18, 2014 at 5:24
  • There's a good article on exactly that problem here. Commented Aug 18, 2014 at 5:32
  • @Michael: IntArray is just an example here. In reality, I'm using things like meshes that might contain both submeshes and textures, for example. And introducing a class that just wraps these two containers seems a bit heavy to me. Commented Aug 18, 2014 at 5:32

2 Answers 2

3

You could create a typedef and refer to that in your function signatures:

class IntArray
{
public:
    typedef std::vector<int> Vec;

    IntArray(const Vec& vals) : vals(vals) {}

    const Vec& getValues() const { return vals; }
    Vec& getValues() { return vals; }

private:
    Vec vals;
};

Now if you want to change the storage type, you just change the typedef:

typedef std::list<int> Vec;
Sign up to request clarification or add additional context in comments.

Comments

0

You can generalise this with your own template:

template<typename CONTAINER>
class IntArray
{
    typedef CONTAINER<int> Vec;
public:
    IntArray(const Vec& vals) : vals(vals) {}
    const Vec& getValues() const { return vals; }
    Vec& getValues() { return vals; }

private:
    Vec vals;
};

Now you can specify the container type at will:

std::list<int> vals { 0, 1, 2, 3, 4 };
IntArray<std::list> arr(vals);
for(int val: arr) {
    // Something
}

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.