vector assign

Discussion in 'C++' started by stephen b, May 23, 2008.

  1. stephen b

    stephen b Guest

    Hi all, personally I'd love to be able to do something like this:

    vector<int> v;
    v.assign(1, 2, 5, 9, 8, 7) etc

    without having to manually add elements by doing v[0] = 1, v[1] = 2 ..
    etc.

    it would make for much more readable code that is faster to write in
    some situations. I've not seen this feature documented anywhere
    though which I find curious. is there another way to achieve this?

    thanks,
    stephen.
     
    stephen b, May 23, 2008
    #1
    1. Advertising

  2. stephen b wrote:
    > it would make for much more readable code that is faster to write in
    > some situations. I've not seen this feature documented anywhere
    > though which I find curious. is there another way to achieve this?


    Maybe using variable arguments and inheritance

    #include <iostream>
    #include <vector>
    #include <stdarg.h>
    #include <iterator>

    template <typename T > class myVec: public std::vector<T>
    {
    public:
    void assign(int amount,...);
    };

    template <typename T > void myVec<T>::assign(int amount,...)
    {
    T val;
    va_list vl;
    va_start(vl,amount);
    for (int i=0;i<amount;i++)
    {
    val=va_arg(vl,T);
    push_back(val);
    }
    va_end(vl);
    }

    int main()
    {

    myVec<int> vec;
    vec.assign(3,2,1,0);
    std::copy(vec.begin(),vec.end(),std::eek:stream_iterator<int>(std::cout,
    " "));
    return 0;
    }

    Darío
     
    Darío Griffo, May 24, 2008
    #2
    1. Advertising

  3. stephen b

    Guest

    On May 23, 3:40 pm, stephen b <> wrote:
    > Hi all, personally I'd love to be able to do something like this:
    >
    > vector<int> v;
    > v.assign(1, 2, 5, 9, 8, 7) etc


    Checkout Boost's Assign Library. You can do these:

    vector<int> v;
    v += 1,2,3,4,5,6,7,8,9;

    or

    vector<int> v = list_of(1)(2)(3);

    etc.

    Ali
     
    , May 24, 2008
    #3
  4. stephen b

    stephen b Guest

    On May 23, 5:48 pm, wrote:
    > On May 23, 3:40 pm, stephen b <> wrote:
    >
    > > Hi all, personally I'd love to be able to do something like this:

    >
    > > vector<int> v;
    > > v.assign(1, 2, 5, 9, 8, 7) etc

    >
    > Checkout Boost's Assign Library. You can do these:
    >
    > vector<int> v;
    > v += 1,2,3,4,5,6,7,8,9;
    >
    > or
    >
    > vector<int> v = list_of(1)(2)(3);


    Thanks, that looks really promising, I'll check it out. Stephen.
     
    stephen b, May 24, 2008
    #4
  5. Daniel T. wrote:
    > Would this work for non-POD types?

    A simple test told me not :(

    compiling test.cpp (g++)
    test.cpp:65: instantiated from here
    test.cpp:56: warning: cannot receive objects of non-POD type 'class A'
    through '...'; call will abort at runtime


    BTW inheritance is not necessary.

    I know, but since we program in OOP paradigm, it seems to me the best
    way to do that.

    >
    > template < typename T >
    > void assign( std::vector<T>& vec, int count, ... )
    > {
    > va_list vl;
    > va_start( vl, count );
    > for ( int i=0; i!= count; ++i)
    > {
    > vec.push_back( va_arg( vl, T ) );
    > }
    > va_end(vl);
    > }
    >
    > using namespace std;
    >
    > int main()
    > {
    > vector<int> vec;
    > assign( vec, 3, 2, 1, 0 );
    > copy( vec.begin(), vec.end(), ostream_iterator<int>( cout, " " ) );
    > }
    >
    > }
     
    Darío Griffo, May 24, 2008
    #5
  6. stephen b

    Jerry Coffin Guest

    In article <54590b15-eafb-45ca-83ac-3768a65f8e65@
    2g2000hsn.googlegroups.com>, says...
    > Hi all, personally I'd love to be able to do something like this:
    >
    > vector<int> v;
    > v.assign(1, 2, 5, 9, 8, 7) etc
    >
    > without having to manually add elements by doing v[0] = 1, v[1] = 2 ..
    > etc.
    >
    > it would make for much more readable code that is faster to write in
    > some situations. I've not seen this feature documented anywhere
    > though which I find curious. is there another way to achieve this?


    If you have a predefined set of elements (and that's all the vector will
    need to hold) you might want to look into using TR1::array instead of a
    vector (the same class is in the current draft for C++ 0x as std::array
    as well).

    If you will/might need to expand the collection later, you'll still need
    to use a vector, but you can initialize the array from the constants,
    and then initialize the vector from the array:

    TR1::array<int> a = {1, 2, 5, 9, 8, 7};

    std::vector<int>v(a.begin(), a.end());

    That may not be perfect, but it's still pretty decent.

    There have been a number of other methods invented, but none of them is
    particularly clean. I once wrote a bit of code to deal with this
    problem, but it's sufficiently ugly that I never use it myself, so I'd
    have some difficulty recommending that anybody else do so either:

    template<class T>
    class fill_vector {
    std::vector<T> data;
    public:
    fill_vector(T const &val) {
    data.push_back(val);
    }

    fill_vector<T> &operator,(T const &t) {
    data.push_back(t);
    return *this;
    }

    operator std::vector<T>() { return data; }
    };

    template<class T>
    fill_vector<T> fillVect(T const &t) {
    return fill_vector<T>(t);
    }

    std::vector<int> iv = (fillVect(1), 2, 5, 9, 8, 7);

    I wouldn't mind if the code for fill_vector or fill_vect was ugly, but
    the code to use them needs those seemingly extraneous parentheses, so
    the code that uses this technique is unavoidably rather ugly. That
    really _does_ bother me.

    Another direction is to start with an array, and just have a reasonably
    clean way of supplying iterators to the beginning and end of the array
    so you can initialize the vector from it cleanly:

    template <class T, size_t N>
    T *end(T (&input)[N]) {
    return input+N;
    }

    int init[] = { 1, 2, 5, 9, 8, 7};

    std::vector<int> v(init, end(init));

    Like the version that initializes a vector from a TR1::array, this
    separates creation of the vector from defining its initial data, and
    requires a name for the object holding that initial data. That's not
    really ideal, but in practice I've never really run into a major problem
    with it either.

    Choosing between TR1::array and/or std::array and this last version,
    isn't necessarily simple. If you already have the array class available
    (on all compilers you need to target), you might as well use it. If you
    don't have it available, you need to decide whether the number of times
    you could use an array object directly (rather than just to initialize a
    vector) justifies finding and installing an implementation. That'll
    depend on circumstances about which I know too little to comment
    intelligently.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, May 24, 2008
    #6
  7. stephen b

    James Kanze Guest

    On May 24, 1:48 am, wrote:
    > On May 23, 3:40 pm, stephen b <> wrote:


    > > Hi all, personally I'd love to be able to do something like this:


    > > vector<int> v;
    > > v.assign(1, 2, 5, 9, 8, 7) etc


    > Checkout Boost's Assign Library. You can do these:


    > vector<int> v;
    > v += 1,2,3,4,5,6,7,8,9;


    Institutionalized obfuscation, anyone? That statement has a
    predefined meaning in C++, without any library, and any code
    which changes a predefined meaning should be avoided at all
    costs.

    > or


    > vector<int> v = list_of(1)(2)(3);


    That's better. A lot of the time, of course, simply:

    static int const init[] = { 1, 2, 5, 9, 8, 7 } ;
    std::vector< int > v( begin( init ), end( init ) ) ;

    is just as good.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 24, 2008
    #7
  8. stephen b

    James Kanze Guest

    On May 24, 8:01 am, Jerry Coffin <> wrote:
    > In article <54590b15-eafb-45ca-83ac-3768a65f8e65@
    > 2g2000hsn.googlegroups.com>, says...


    > If you will/might need to expand the collection later, you'll
    > still need to use a vector, but you can initialize the array
    > from the constants, and then initialize the vector from the
    > array:


    > TR1::array<int> a = {1, 2, 5, 9, 8, 7};


    Can TR1::array deduce the length from the number of elements in
    the initialization list? (And if so, how?)

    IIUC, the standard is extending initialization syntax
    expressedly to deal with such cases (and will allow an
    initialization list directly in the definition of the vector),
    but I didn't think that it could be done today.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 24, 2008
    #8
  9. Hi!

    Darío Griffo schrieb:
    >> BTW inheritance is not necessary.

    >
    > I know, but since we program in OOP paradigm, it seems to me the best
    > way to do that.


    No. It is not the best way although we have "OOP" at our disposal (I
    think of "OOP" here as "derive from a base class"). A vector makes no
    good base class. You must not derive from it. Value based classes are
    usually not suited for inheritance. Think of a "long" derived from an
    "int"!?

    A better way to do it is to write a complete wrapper and add
    functionality as needed:

    template<typename T>
    class AssignableVector
    {
    vector<T> data;
    public:
    AssignableVector() {}
    AssignableVector(size_t n, T const t = T())
    : data(n, t)
    {}
    //forward all functions to the vector:
    void push_back(T const t) { data.push_back(t); }
    ...

    //add extra functionality:
    void assign(/*whatever parameters are needed*/) { ... }
    };

    This it much code. And it is boring to write. I guess that's why many
    people resort to inheritance: just to save typing.

    When I can't really convince you not to use inheritance, then at least
    use private inheritance to hide it. (Which means you would have to
    somehow provide public versions of the inherited methods, which needs
    the same typing than above after all).

    Regards,
    Frank
     
    Frank Birbacher, May 24, 2008
    #9
  10. Hi!

    Alf P. Steinbach schrieb:
    > I don't think it's worth it or even a good idea to add more features,
    > but it's easy to do that also, e.g.
    >
    > struct Clear {};
    >
    > template< typename T >
    > std:vector<T>& operator <<( std::vector<T>& v, Clear )
    > {
    > std::vector<T>().swap( v );
    > return v;
    > }
    >
    > enabling things like
    >
    > v << Clear() << 1 << 2 << 3;


    Right, no a good idea, in my opinion.

    v1 << 1 << 2 << Swap(v2 << Clear() << 3 << 3) << v3 << Print(std::cout);

    o_O

    Frank
     
    Frank Birbacher, May 24, 2008
    #10
  11. Hi!

    Alf P. Steinbach schrieb:
    >> IIUC, the standard is extending initialization syntax
    >> expressedly to deal with such cases (and will allow an
    >> initialization list directly in the definition of the vector),
    >> but I didn't think that it could be done today.

    >
    > Good, yet possibly bad. Good for vector. Bad if it isn't more general.


    Meaning from an expression explicitly constructing an object, the final
    type can be deduced from the arguments passed to the constructor? like:

    array<int>({4,5,6}) //deduce size n from use of ctor array(T[n])??

    or:

    ostream_iterator<int>(std::wcout) //deduce wchar_t usage

    ?

    Frank
     
    Frank Birbacher, May 24, 2008
    #11
  12. Hi!

    Daniel T. schrieb:
    > I guess you would have a real problem with the following then? :)
    >
    > template<class T> class Vec : public vector<T> {


    Yes. It doesn't work polymorphically, you know. And you agree.

    void foo(vector<T> const& data)
    {
    data[3]; //should throw, but doesn't ??

    Regards,
    Frank
     
    Frank Birbacher, May 24, 2008
    #12
  13. stephen b

    Jerry Coffin Guest

    In article <5a4cc544-b89a-4c82-8b1f-
    >,
    says...
    > On May 24, 8:01 am, Jerry Coffin <> wrote:


    [ ... ]

    > > TR1::array<int> a = {1, 2, 5, 9, 8, 7};

    >
    > Can TR1::array deduce the length from the number of elements in
    > the initialization list? (And if so, how?)


    Oops -- sorry, but no. You have to supply the size as a template
    parameter. My apologies for the typo.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, May 24, 2008
    #13
  14. stephen b

    James Kanze Guest

    On May 24, 12:34 pm, "Alf P. Steinbach" <> wrote:
    > * James Kanze:
    > > On May 24, 1:48 am, wrote:
    > >> On May 23, 3:40 pm, stephen b <> wrote:


    > >>> Hi all, personally I'd love to be able to do something like this:


    > >>> vector<int> v;
    > >>> v.assign(1, 2, 5, 9, 8, 7) etc


    > >> Checkout Boost's Assign Library. You can do these:


    > >> vector<int> v;
    > >> v += 1,2,3,4,5,6,7,8,9;


    > > Institutionalized obfuscation, anyone? That statement has a
    > > predefined meaning in C++, without any library, and any code
    > > which changes a predefined meaning should be avoided at all
    > > costs.


    > I tend to use "<<" for adding things to some logical
    > container.


    There are arguments both ways. According to some, the
    "abstraction" of << is formatting. At least one specialist even
    argued that it was formatting text. Others consider it simply
    "insertion". If you are of the latter school, it's the obvious
    solution.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 24, 2008
    #14
  15. stephen b

    James Kanze Guest

    On May 24, 12:45 pm, "Alf P. Steinbach" <> wrote:
    > * James Kanze:


    > > On May 24, 8:01 am, Jerry Coffin <> wrote:
    > >> In article <54590b15-eafb-45ca-83ac-3768a65f8e65@
    > >> 2g2000hsn.googlegroups.com>, says...


    > >> If you will/might need to expand the collection later, you'll
    > >> still need to use a vector, but you can initialize the array
    > >> from the constants, and then initialize the vector from the
    > >> array:


    > >> TR1::array<int> a = {1, 2, 5, 9, 8, 7};


    > > Can TR1::array deduce the length from the number of elements
    > > in the initialization list? (And if so, how?)


    > No, it's just ordinary POD initialization (no constructors in
    > that class).


    That was my believe as well, but every time I think something
    can't be done, someone comes up with some metaprogramming trick
    to do it.

    > So above seems to be a typo, missing size parameter.


    > > IIUC, the standard is extending initialization syntax
    > > expressedly to deal with such cases (and will allow an
    > > initialization list directly in the definition of the vector),
    > > but I didn't think that it could be done today.


    > Good, yet possibly bad. Good for vector. Bad if it isn't
    > more general.


    It will definitely be more general. I've not really looked at
    it myself, so I don't know the details, but I think the idea is
    that it will work for any type which has a two iterator
    constructor.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 24, 2008
    #15
  16. stephen b

    stephen b Guest

    > > Checkout Boost's Assign Library. You can do these:
    > > vector<int> v;
    > > v += 1,2,3,4,5,6,7,8,9;

    >
    > Institutionalized obfuscation, anyone?  That statement has a
    > predefined meaning in C++, without any library, and any code
    > which changes a predefined meaning should be avoided at all
    > costs.


    I can't find a definition anwyhere of what the += operator does with
    vectors. I'd be happy if, say, v += 2 iterated over the vector and
    added the value 2 to each element. similarly if v *= 5 multiplied all
    elements then I'd find that really useful too. In the name of brevity
    of course.

    Stephen.
     
    stephen b, May 25, 2008
    #16
  17. stephen b

    stephen b Guest

    > > Checkout Boost's Assign Library. You can do these:
    > > vector<int> v;
    > > v += 1,2,3,4,5,6,7,8,9;

    >
    > Institutionalized obfuscation, anyone? That statement has a
    > predefined meaning in C++, without any library, and any code
    > which changes a predefined meaning should be avoided at all
    > costs.


    I can't find a definition anwyhere of what the += operator does with
    vectors. I'd be happy if, say, v += 2 iterated over the vector and
    added the value 2 to each element. similarly if v *= 5 multiplied all
    elements then I'd find that really useful too. In the name of brevity
    of course.

    Stephen.
     
    stephen b, May 25, 2008
    #17
  18. stephen b

    Jerry Coffin Guest

    In article <52b853c6-adcc-4628-9585-
    >,
    says...

    [ ... ]

    > I can't find a definition anwyhere of what the += operator does with
    > vectors.


    Unless you provide an overloaded operator+= that does something, it
    simply generates an error.

    > I'd be happy if, say, v += 2 iterated over the vector and
    > added the value 2 to each element. similarly if v *= 5 multiplied all
    > elements then I'd find that really useful too. In the name of brevity
    > of course.


    If that's what you want, take a look at valarray.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, May 25, 2008
    #18
  19. stephen b

    James Kanze Guest

    On May 25, 2:59 am, stephen b <> wrote:
    > > > Checkout Boost's Assign Library. You can do these:
    > > > vector<int> v;
    > > > v += 1,2,3,4,5,6,7,8,9;


    > > Institutionalized obfuscation, anyone? That statement has a
    > > predefined meaning in C++, without any library, and any code
    > > which changes a predefined meaning should be avoided at all
    > > costs.


    > I can't find a definition anwyhere of what the += operator
    > does with vectors.


    There isn't any, of course, but there is one for string, and it
    doesn't take too much imagination to extend it to vector.

    There is a well defined meaning for the comma operator,
    however. And the above breaks it. It also breaks the rule that
    x += y should have the same behavior as x = x + y, modulo the
    fact that in one, x is evaluated twice, and in the other only
    once. The fact that:
    v += 1,2,3,4,5,6,7,8,9;
    and
    v = 1,2,3,4,5,6,7,8,9;
    mean completely different things is pure obfuscation, and won't
    be allowed by any reasonable coding guideline.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 25, 2008
    #19
  20. James Kanze schrieb:
    >>> IIUC, the standard is extending initialization syntax
    >>> expressedly to deal with such cases (and will allow an
    >>> initialization list directly in the definition of the vector),
    >>> but I didn't think that it could be done today.

    >
    >> Good, yet possibly bad. Good for vector. Bad if it isn't
    >> more general.

    >
    > It will definitely be more general. I've not really looked at
    > it myself, so I don't know the details, but I think the idea is
    > that it will work for any type which has a two iterator
    > constructor.


    No, you have to write an extra sequence constructor in this form:

    struct Container
    {
    Container(initializer_list<Type> seq)
    {
    // do something with seq.begin(), .end() and .size(), ex.:
    assign(seq.begin(), seq.end());
    }
    }

    From what I have read, an initializer can be used quite everywhere, so
    you can pass it to a function or return it:

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

    SetColor( {1.0, 0.0, 0.0} ); // sets a RGB color value for red

    --
    Thomas
     
    Thomas J. Gritzan, May 25, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. pmatos
    Replies:
    6
    Views:
    24,122
  2. Replies:
    8
    Views:
    1,998
    Csaba
    Feb 18, 2006
  3. Chris Roth

    Vector Assign vs Vector operator=

    Chris Roth, Feb 21, 2007, in forum: C++
    Replies:
    4
    Views:
    392
    Ron Natalie
    Feb 22, 2007
  4. Javier
    Replies:
    2
    Views:
    621
    James Kanze
    Sep 4, 2007
  5. Rushikesh Joshi
    Replies:
    0
    Views:
    395
    Rushikesh Joshi
    Jul 10, 2004
Loading...

Share This Page