views:

105

answers:

2

Is there any way to use the += operator with a vector without using boost or using a derivated class?

Eg.

somevector += 1, 2, 3, 4, 5, 6, 7;

would actually be

somevector.push_back(1);
somevector.push_back(2);
somevector.push_back(3);
etc.
+4  A: 

Not with syntax like that, no. But you could do something like this:

int tmparray[] = {1, 2, 3, 4, 5, 6, 7};

somevector.insert(somevector.end(), &tmparray, &tmparray + sizeof(tmparray));
Tyler McHenry
+1: gets the job done, perfectly readable.
Justin Ardini
I'll use this if I can't find a better soloution :) My syntax is what I found in a source file not made by me, uses boost and compilies fine on MSVC. But I'm using MinGW
kotarou3
Boost likes to do all sorts of weird magic with operator overloading that makes the C++ syntax do all sorts of stuff it was never meant to. That's not a bad thing, but don't expect to find the same kind of cleverness in the standard library.
Tyler McHenry
sellibitze
+6  A: 

With a little ugly operator overloading, this isn't too difficult to accomplish. This solution could easily be made more generic, but it should serve as an adequate example.

#include <vector>

Your desired syntax uses two operators: the += operator and the , operator. First, we need to create a wrapper class that allows us to apply the , operator to push an element onto the back of a vector:

template <typename T>
struct push_back_wrapper
{
    explicit push_back_wrapper(std::vector<T>& v) : v_(&v) { }

    push_back_wrapper& operator,(const T& x)
    {
        v_->push_back(x);
        return *this;
    }

    std::vector<T>* v_;
};

Then, in order to use this in conjunction with += on a vector, we overload the += operator for a vector. We return a push_back_wrapper instance so that we can chain push backs with the comma operator:

template <typename T, typename U>
push_back_wrapper<T> operator+=(std::vector<T>& v, const U& x)
{
    v.push_back(x);
    return push_back_wrapper<T>(v);
}

Now we can write the code you have in your example:

int main()
{
    std::vector<int> v;
    v += 1, 2, 3, 4, 5, 6, 7;
}

The v += 1 will call our operator+= overload, which will return an instance of the push_back_wrapper. The comma operator is then applied for each of the subsequent elements in the "list."

James McNellis
Oh, so the comma was also an overload in boost? o.o
kotarou3
Yep, that's pretty much what boost is doing. It's a bit of an abuse of the `,` operator, since that's not what the comma operator normally does, but it's perfectly legal C++. The C++ syntax can be made to do very strange things: http://www.xs4all.nl/~weegen/eelis/analogliterals.xhtml
Tyler McHenry
@Tyler: Ha ha ha. I **love** the analog literals. Pure ingenuity. As for this (ab)use of the comma operator, I don't think I would use this in production code. However, I do use a set of `+` and `+=` overloads to append a single element, a vector of elements, or a range of elements onto the back of a vector. I did enjoy writing this, though... :-P
James McNellis
Hmm, what exactly is U used for?
kotarou3
@kotarou3: If we used `T` for both parameters, then instantiation of the template would fail if we tried to do `vector<int> v; v += 3.0;`, because the first argument of the `+=` is of type `vector<int>`, so `T` would have to be `int`, but the second argument is of type `double,` so `T` would have to be `double`. It can't be both. By using a second type parameter, we can allow implicit conversions to take place as we would expect them to. It isn't a problem with the `,` overload because the `,` overload is not itself a function template, it's a member function of a class template.
James McNellis