To add the method append for all sequential containers that have method push_back

295 views
Skip to first unread message

Vlad from Moscow

unread,
Oct 20, 2013, 3:57:04 PM10/20/13
to std-pr...@isocpp.org
I find out some inconvenience that sequential containers except std::basic_string that have method push_back at the same time have no method append.
 
For example it would be not bad to write
 
std::vector<int> v;
// processing of v
 
std::list<int> l;
// processing of l
 
v.append( l.begin(), l.end() );
 
Although the same can be done with method insert as for example
 
v.insert( v.end(), l.begin(), l.end() );
 
I would prefer to use append because it has more clear semantic and interchangeable with method the append of std::basic_string.
 
I would like to make such a proposal.
 
Are any thoughts about adding the method append to sequantial containers?

Billy O'Neal

unread,
Oct 20, 2013, 11:48:17 PM10/20/13
to std-proposals
+1

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


--
 
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

Klaim - Joël Lamotte

unread,
Oct 21, 2013, 6:25:40 PM10/21/13
to std-pr...@isocpp.org
+1 too, I'm getting in this use case very often and clarifying would help (btw doesn't it suggests more information to the implementation to use for potential optimizations?).

Vlad from Moscow

unread,
Oct 21, 2013, 7:00:14 PM10/21/13
to std-pr...@isocpp.org
I think that three overloaded functions could be provided for the method append. They are
 
append( size_type n, const T &value );
 
template <class InputIterator>
append( InputIterator first, InputIterator last );
 
append( initializer_list<T> );
 
I have not specified the return type because opposite to method insert I would propose that the method append would return reference to the container itself.
 
The question regarding to the return type should be discussed.
 

вторник, 22 октября 2013 г., 2:25:40 UTC+4 пользователь Klaim - Joël Lamotte написал:

Evgeny Panasyuk

unread,
Oct 21, 2013, 7:06:33 PM10/21/13
to std-pr...@isocpp.org
Are any thoughts about adding the method append to sequantial containers?

Vlad from Moscow

unread,
Oct 21, 2013, 7:08:45 PM10/21/13
to std-pr...@isocpp.org
No, I do not think so. It is common interface of all sequential containers including and together with std::basic_string.

вторник, 22 октября 2013 г., 3:06:33 UTC+4 пользователь Evgeny Panasyuk написал:

Evgeny Panasyuk

unread,
Oct 21, 2013, 7:20:59 PM10/21/13
to std-pr...@isocpp.org

No, I do not think so.

Why not?
 
It is common interface of all sequential containers including and together with std::basic_string.

Just read GotW #84.
std::string has many controversial design decisions. We should not uglify STL by borrowing bad stuff from std::string.

Bengt Gustafsson

unread,
Oct 22, 2013, 3:56:50 AM10/22/13
to std-pr...@isocpp.org
I think the idea is good, this use case appears quite often. But why not overload push_back with more signatures instead of introducing a new name? The signatures available would then be exactly parallel to insert(), with the difference that the first parameter is absent.

Billy O'Neal

unread,
Oct 22, 2013, 4:02:26 AM10/22/13
to std-proposals
1. Because adding overloads to an existing function name is a perilous exercise :)
2. Because "push" means "add 1 item".

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


--

Vlad from Moscow

unread,
Oct 22, 2013, 7:57:31 AM10/22/13
to std-pr...@isocpp.org
 
I do not see any great sense in this function. In fact you need to write its realization for each container. So it looks like the realization of function std:;swap in containers. Moreover std::basic_string has already method append. So that to make the call of the function interchangeable with other containers it is better to make it a class member.
.
вторник, 22 октября 2013 г., 3:20:59 UTC+4 пользователь Evgeny Panasyuk написал:

Vlad from Moscow

unread,
Oct 22, 2013, 8:04:49 AM10/22/13
to std-pr...@isocpp.org
Taking into account method append of std::basic_string it is not a new name. append and insert will have differenct semantic. append will return reference to the container itself. So you can use it for example the follwoing way
 
std::vector<int> v = { 1, 2, 3, 4, 5 };
 
for ( int x : v.append( { 4, 3, 2, 1 } ) ) std::cout << x << ' ';
 
insert is used then you need the position after inserting new elements. For example
 
auto pos = v.end();
 
pos = v.insert( pos, { 4, 3, 2, 1 } );
v.insert( pos, 5 );

вторник, 22 октября 2013 г., 11:56:50 UTC+4 пользователь Bengt Gustafsson написал:

Billy O'Neal

unread,
Oct 22, 2013, 1:37:19 PM10/22/13
to std-proposals
I suppose I understand why there's no append here -- append on basic_string is the same thing effectively as operator+= -- but there's no such semantic operation that makes sense for vector.

I suppose there's no reason for someone who wants this semantic not to do:

template <typename T, typename InputIterator>
T& append(T& container, InputIterator first, InputIterator last)
{
    container.insert(container.end(), first, last);
    return container;
}

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


--

Evgeny Panasyuk

unread,
Oct 22, 2013, 1:38:05 PM10/22/13
to std-pr...@isocpp.org
 
I do not see any great sense in this function. In fact you need to write its realization for each container. So it looks like the realization of function std:;swap in containers. Moreover std::basic_string has already method append. So that to make the call of the function interchangeable with other containers it is better to make it a class member.
 
Non-member append/push_back is easily implementable in terms of end() (which is part of Container concept requirnment since 1998) and insert(...) (which is part of Sequence concept requirenment since 1998).
Once such function will be implemented as non-member it would work with any conformant sequence automaticly. That is not only about STL containers, but also about containers which users developed themself since 1998.
Just look at http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/range/reference/algorithms/new/push_back.html

Vlad from Moscow

unread,
Oct 22, 2013, 4:03:53 PM10/22/13
to std-pr...@isocpp.org
 
In this case you can not substituted a call of the method for std::basic_string with a call for a vector. So the interface will not be consistent.
 
Apart from this the call
 
std::cout << v.append( { 1, 2, 3, 4, 5 } );
 
looks semantically more clear than
 
std::cout << append( v, { 1, 2, 3, 4, 5 } );
 
From the second call it is not clear what is outputed whether it is a new vector or it is the original vector.

вторник, 22 октября 2013 г., 21:37:19 UTC+4 пользователь Billy O'Neal написал:

Billy O'Neal

unread,
Oct 22, 2013, 4:09:59 PM10/22/13
to std-proposals
>From the second call it is not clear what is outputed whether it is a new vector or it is the original vector.

I disagree. You can use nonmember append with basic_string, and the name "append" implies modifying the original vector. There's nothing about the syntactical difference between member and nommember functions which clearly indicates "this modifies" or "this does not modify".

That is, there's no reason "v.append(xyz)" doesn't return a different vector either, by this logic.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 22, 2013, 4:11:02 PM10/22/13
to std-pr...@isocpp.org
As I said I do not see a great sense to make the method as a non-member function. In my opinion it is a wrong approach because if to do so the question arises what to do with arrays. They have no method insert. Also what to do with other containers that also have no method insert as for example std::forward_list?

вторник, 22 октября 2013 г., 21:38:05 UTC+4 пользователь Evgeny Panasyuk написал:

Billy O'Neal

unread,
Oct 22, 2013, 4:13:40 PM10/22/13
to std-proposals
> if to do so the question arises what to do with arrays
You should not be able to append to arrays. An append is a length changing operation, and arrays are fixed size.

>Also what to do with other containers that also have no method insert as for example std::forward_list?
Use tag dispatch for forward_list to call insert_after instead.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Evgeny Panasyuk

unread,
Oct 22, 2013, 4:15:08 PM10/22/13
to std-pr...@isocpp.org
 
In this case you can not substituted a call of the method for std::basic_string with a call for a vector. So the interface will not be consistent.

What? Do you want to turn std::vector into std::string-like bloat?

Apart from this the call
 
std::cout << v.append( { 1, 2, 3, 4, 5 } );
 
looks semantically more clear than

No, it is common practice to prefer non-member functions over members. It increases generality, encapsulation, etc.
Just read works of Stepanov, Stroustrup, Alexandrescu, Mayers, Sutter.
 
 
std::cout << append( v, { 1, 2, 3, 4, 5 } );
 
From the second call it is not clear what is outputed whether it is a new vector or it is the original vector.

I don't see anything special in member-version that makes it semanticaly cleaner.


Vlad from Moscow

unread,
Oct 22, 2013, 4:17:46 PM10/22/13
to std-pr...@isocpp.org
If v.append( /*...*/ ) indeed will not return the vector itself then I could agree with you that a non-member function can be introduced. But in my opinion only this call
 
append( v, { 1, 2, 3, 4 } )
 
can arise a question what is actually returned.

среда, 23 октября 2013 г., 0:09:59 UTC+4 пользователь Billy O'Neal написал:

Billy O'Neal

unread,
Oct 22, 2013, 4:18:42 PM10/22/13
to std-proposals
I don't see why
append( v, { 1, 2, 3, 4 } )
raises any more question about what is actually returned when compared with
v.append( { 1, 2, 3, 4 } )

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 22, 2013, 4:24:12 PM10/22/13
to std-pr...@isocpp.org
In my opinion append is a property of a container. Arrays have no such a property, std::array also has no such a property. Associative containers also have no such a property. std::forward_list has no method insert. So a general function will only conduse users.
 
And your "general practice" is not applied in this case because as I said it is a property of a container.
 

среда, 23 октября 2013 г., 0:15:08 UTC+4 пользователь Evgeny Panasyuk написал:

Evgeny Panasyuk

unread,
Oct 22, 2013, 4:26:27 PM10/22/13
to std-pr...@isocpp.org
As I said I do not see a great sense to make the method as a non-member function. In my opinion it is a wrong approach because if to do so the question arises what to do with arrays.

It will just fail to compile, just as it should.

They have no method insert. Also what to do with other containers that also have no method insert as for example std::forward_list?

There are ways to implement special versions for std::forward_list, like overloading.
But at first, which semantic you want to have for append( fwd_list, ... ) ? std::forward_list does not even have push_back - I think it should just fail on append.

Joel Falcou

unread,
Oct 22, 2013, 4:24:12 PM10/22/13
to std-pr...@isocpp.org
On 22/10/2013 22:24, Vlad from Moscow wrote:
> In my opinion append is a property of a container. Arrays have no such
> a property, std::array also has no such a property. Associative
> containers also have no such a property. std::forward_list has no
> method insert. So a general function will only conduse users.
> And your "general practice" is not applied in this case because as I
> said it is a property of a container.
>

- append on std array can just return a new array with a larger size and
new elements.
- the fact append doesn't work on associative container an just be
implented with either concept overloading on the container properties
(when concept are in) or fallback to a static_assert.
- std::forward_list can also reconstruct a new, larger list with
appended data

i don't see why it hsould be limited really

Billy O'Neal

unread,
Oct 22, 2013, 4:30:14 PM10/22/13
to std-proposals
>append on std array can just return a new array with a larger size and new elements.
It could, but that's sufficiently different from what append does in other cases, it shouldn't do that. The word for this would be "concat", which would be just fine for std::array (as well as other containers).

And actually, I'm not sure it could in all cases -- e.g. if the begin / end iterator pair size is not known at compile time.

>std::forward_list can also reconstruct a new, larger list with appended data
Same comment as before. That would not be an append, it would be a concat. If there should be nonmember concat that's one thing, but what you describe is not an append. The word "append" implies that the original sequence was modified.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


--

--- You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

Ville Voutilainen

unread,
Oct 22, 2013, 4:32:38 PM10/22/13
to std-pr...@isocpp.org
On 22 October 2013 23:18, Billy O'Neal <billy...@gmail.com> wrote:
I don't see why
append( v, { 1, 2, 3, 4 } )
raises any more question about what is actually returned when compared with
v.append( { 1, 2, 3, 4 } )



I don't think adding a free append function helps anybody. It doesn't really fit into the existing
style of container modifiers, so it would be quite an oddball function. And adding a
new member function for the various containers gets a "meh" from me, too.

Evgeny Panasyuk

unread,
Oct 22, 2013, 4:34:52 PM10/22/13
to std-pr...@isocpp.org

In my opinion append is a property of a container.

Why?
 
Arrays have no such a property, std::array also has no such a property.

Great, it will fail to compile. What is problem?
 
Associative containers also have no such a property. std::forward_list has no method insert. So a general function will only conduse users.

 I don't see problem here either.

And your "general practice" is not applied in this case because as I said it is a property of a container.


STL containers are not only one containers that exist. There are many others.
For instance non-member append would work with boost::container::vector or boost::container::deque without any modification.
There are also proprietary containers which are not even in public domain - such append would work on them too.
I just don't see any reason why you want to duplicate that method for each container.

Billy O'Neal

unread,
Oct 22, 2013, 4:34:41 PM10/22/13
to std-proposals
Yeah, this should really start as a cohesive library first e.g. in Boost with other similar functions things go that way. Also depends on what we get out of the Ranges SG.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Evgeny Panasyuk

unread,
Oct 22, 2013, 4:40:14 PM10/22/13
to std-pr...@isocpp.org
Yeah, this should really start as a cohesive library first e.g. in Boost with other similar functions things go that way.
Also depends on what we get out of the Ranges SG.

Plus, interface depends on which concepts we would get.

Vlad from Moscow

unread,
Oct 22, 2013, 4:52:06 PM10/22/13
to std-pr...@isocpp.org
At least because as a general rule if a function that  deals with two objects and is declared as a member function it usually returns reference to "this" object. On the other hand, if such a function is declared as a non-member function it usually returns a new object. 
Moreover this call
 
append( v, { a, 2, 3, 4 } );
 
looks like two containers are used so any reader can not exclude that the function is declared as
 
std::vector<int> append( const std::vector<int> &v1, const std::vector<int> &v2 );
 
A non-member function append looks like operator overloading in C# where overloaded operators are declared as static member functions and return a new object.

среда, 23 октября 2013 г., 0:18:42 UTC+4 пользователь Billy O'Neal написал:

Vlad from Moscow

unread,
Oct 22, 2013, 4:54:47 PM10/22/13
to std-pr...@isocpp.org

среда, 23 октября 2013 г., 0:26:27 UTC+4 пользователь Evgeny Panasyuk написал:
It is a good note. It seems you are starting to understand that append is a property of a container. Look how I named the thread.
 
 

Vlad from Moscow

unread,
Oct 22, 2013, 5:01:46 PM10/22/13
to std-pr...@isocpp.org
In this case we will have different semantics. In my opinion it is not a good idea. I am sure that append should be introduced only for sequantial containers that have method push_back as std::basic_string, std::vector, std::deque, std::list, and std::x_forward_list for which I am going to write a proposal as I already announced in this forum.

среда, 23 октября 2013 г., 0:24:12 UTC+4 пользователь Joel Falcou написал:

Evgeny Panasyuk

unread,
Oct 22, 2013, 5:03:11 PM10/22/13
to std-pr...@isocpp.org

At least because as a general rule if a function that  deals with two objects and is declared as a member function it usually returns reference to "this" object. On the other hand, if such a function is declared as a non-member function it usually returns a new object. 

Where did this rule come from?

Ville Voutilainen

unread,
Oct 22, 2013, 5:03:43 PM10/22/13
to std-pr...@isocpp.org
On 22 October 2013 23:52, Vlad from Moscow <vlad....@mail.ru> wrote:
At least because as a general rule if a function that  deals with two objects and is declared as a member function it usually returns reference to "this" object. On the other hand, if such a function is


I'm pretty sure there's no such general rule in the standard.

Evgeny Panasyuk

unread,
Oct 22, 2013, 5:05:53 PM10/22/13
to std-pr...@isocpp.org
There are ways to implement special versions for std::forward_list, like overloading.
But at first, which semantic you want to have for append( fwd_list, ... ) ? std::forward_list does not even have push_back - I think it should just fail on append.
It is a good note. It seems you are starting to understand that append is a property of a container. Look how I named the thread.

Different containers fulfil different concepts. For some append can be easily implemented, for others not.
But that is not reasoning for member version.

Evgeny Panasyuk

unread,
Oct 22, 2013, 5:11:06 PM10/22/13
to std-pr...@isocpp.org
In this case we will have different semantics. In my opinion it is not a good idea. I am sure that append should be introduced only for sequantial containers that have method push_back as std::basic_string, std::vector, std::deque, std::list, and std::x_forward_list

Why not just make non-member function which works for all sequence containers?
 
for which I am going to write a proposal as I already announced in this forum.

Do you want to modify requirements of sequence container with member that does not add any value?

Vlad from Moscow

unread,
Oct 22, 2013, 5:20:40 PM10/22/13
to std-pr...@isocpp.org
I do not like the idea that some non-member functions will be defined only for narrow groups of containers. It will only confuse users. Besides it will look strange that std::forward_list will be excluded from sequantial containers relative to this function.

среда, 23 октября 2013 г., 1:11:06 UTC+4 пользователь Evgeny Panasyuk написал:

Evgeny Panasyuk

unread,
Oct 22, 2013, 5:30:52 PM10/22/13
to std-pr...@isocpp.org
I do not like the idea that some non-member functions will be defined only for narrow groups of containers.

Some algorithms (non-member function templates) are defined only for narrow groups of ranges.
There is nothing special in append case.
 
It will only confuse users. Besides it will look strange that std::forward_list will be excluded from sequantial containers relative to this function.

There is no surprise - because it supports only part of Sequence container requirements - Table 100.
Moreover - there is no efficient way to implement append for it.

Vlad from Moscow

unread,
Oct 22, 2013, 5:43:13 PM10/22/13
to std-pr...@isocpp.org

среда, 23 октября 2013 г., 1:30:52 UTC+4 пользователь Evgeny Panasyuk написал:
In my opinion it will only confuse users. What about other non-member functions that couldl be introduced and will deal with nerrow groups of containers? append is a property of few containers. It is what distiguishes them from other containers.

Vlad from Moscow

unread,
Oct 22, 2013, 5:48:29 PM10/22/13
to std-pr...@isocpp.org
append should be considered as widening of the semantic of push_back and nothing more.

среда, 23 октября 2013 г., 1:43:13 UTC+4 пользователь Vlad from Moscow написал:

Vlad from Moscow

unread,
Oct 22, 2013, 5:57:56 PM10/22/13
to std-pr...@isocpp.org
append should be considered as widening of the semantic of push_back and nothing more. For example in class std::vector there is method insert that allows to insert one element
 

iterator insert(const_iterator position, const T& x);

is not there?
 
At the same time insert allows to insert several elemnts
 

iterator insert(const_iterator position, size_type n, const T& x);

template <class InputIterator>

iterator insert(const_iterator position,

InputIterator first, InputIterator last);

iterator insert(const_iterator position, initializer_list<T> il);

The same must be valid with push_back. It allows to append one element. What I want that it also would allow to append several elements as insert does. Only push_back will be used through its alias append when several elements are needed to append.
 
That is all.

среда, 23 октября 2013 г., 1:48:29 UTC+4 пользователь Vlad from Moscow написал:

Billy O'Neal

unread,
Oct 22, 2013, 6:56:04 PM10/22/13
to std-proposals
> if such a function is declared as a non-member function it usually returns a new object.

I disagree with that. Example: std::swap.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 23, 2013, 5:59:23 AM10/23/13
to std-pr...@isocpp.org
To demonstrate the advantage of the method append let;s consider a simple assignment.
Let;s assume that there are a vector of strings and three separate strings that have to be appended to the vector.
 
std::vector<std::string> v;
std::string s1 = "Dolce";
std::string s2 = " & ";
std::string s3 = "Gabbana";
 
Having the method append we could write simply
 
std:: cout << v.append( s1 ).append( s2 ).append( s3 );
 
I intentially have written the expression in one line to demonstrate the advantage of the method append.
 
The result of the expression will be
 
Dolce & Gabbana
 
Now let;s substitute append for insert. We could write for example
 
v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 );
 
But how to output the result vector? We can not write simply
 
std::cout << v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 );
 
because the type of the method insert is std::vector<std::string>::iterator. We even can not write the following way
 
std::cout << *v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 );
 
because only one element of the vector will be displayed.
 
Can we use std::copy? For example
 
std::copy( v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 ), v.end(),
                std::ostream_iterator<std::string>( std::cout ) );
 
No, we can not!
Because v.end() will be invalid iterator if it will be calculated before the left operand.
 
So we have only one possibility
 
v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 );
std::cout << v;
 
And we will get
 
Gabbana & Dolce
 
Compare the simple expression
 
std:: cout << v.append( s1 ).append( s2 ).append( s3 );
 
with the difficulties we had to overcome with insert. Moreover the result does not coinside with the needed result.
 
So the expression with insert must be rewritten. But we have now another problem. The expression can not be written in one line the same way as the expression with append. So the only way is to write
 
v.insert( v.cend(), s1 );
v.insert( v.cend(), s2 );
v.insert( v.cend(), s3 );
 
std::cout << v;
 
We had to use three times v.cend(). It is totally useless information because our intention was clear enough: we wanted to append strings. It is obvious without using v.cend() each time that we want to append a new string at the end of the vector.
Method append() expresses this intention very clear without any superfluous parameter that we need each time duplicate if we are going to use insert.
 
So method append *appends* method push_back when a range of new data is used the same way as method insert with ranges appends method insert with one inserted data.

среда, 23 октября 2013 г., 1:57:56 UTC+4 пользователь Vlad from Moscow написал:

Vlad from Moscow

unread,
Oct 23, 2013, 6:11:52 AM10/23/13
to std-pr...@isocpp.org
I am sorry. I made a mistake. To output the vector I should use the range-based for llop. I simply thought about std::basic_string when I were writing about the vector.
 
So the expression will be written as
 
for ( std:;string s :  v.append( s1 ).append( s2 ).append( s3 ) ) std::cout << s;
 
Also I would like to point out that if I wanted to substitute the vector for std::basic_string nothing would be changed!
 
std::string s;
 
std::cout << s.append( s1 ).append( s2 ).append( s3 ) );
 

среда, 23 октября 2013 г., 13:59:23 UTC+4 пользователь Vlad from Moscow написал:

Ville Voutilainen

unread,
Oct 23, 2013, 7:08:43 AM10/23/13
to std-pr...@isocpp.org
On 23 October 2013 12:59, Vlad from Moscow <vlad....@mail.ru> wrote:

 
So we have only one possibility
 
v.insert( v.insert( v.insert( v.end(), s1 ), s2 ), s3 );
std::cout << v;

That's not the only possibility, you can wrap the operation in a lambda and
output the result of the lambda invocation.


Vlad from Moscow

unread,
Oct 23, 2013, 7:44:50 AM10/23/13
to std-pr...@isocpp.org
Yes, you can. But it will not look very well taking into account a possible interchangeability with std::basic_string. It only makes the code more compound and less intuitivily clear.
 
For example if there is a function declared as
 
std:;vector<std:;string> & f( std::vector<std:;string> & );
 
it will be more readable and clear to call it as
 
std::vector<std::string> v( 1, "Hello " );
f( v.append( "World" ) );
 
than to use a lambda expression as the argument.
 

среда, 23 октября 2013 г., 15:08:43 UTC+4 пользователь Ville Voutilainen написал:

Vlad from Moscow

unread,
Oct 23, 2013, 7:48:32 AM10/23/13
to std-pr...@isocpp.org
Or even as
 
std::vector<std::string> v( 1, "Hello " );
f( v.append( { "World ", "Let ", "use ", "method ", "append!" } ) );

среда, 23 октября 2013 г., 15:44:50 UTC+4 пользователь Vlad from Moscow написал:

Nevin Liber

unread,
Oct 23, 2013, 7:51:32 AM10/23/13
to std-pr...@isocpp.org
On 23 October 2013 07:44, Vlad from Moscow <vlad....@mail.ru> wrote:
Yes, you can. But it will not look very well taking into account a possible interchangeability with std::basic_string.

That's pretty much true of *anything* in the basic_string interface that isn't in the interface of the other containers...

I'm pretty much meh (aka neutral to weakly against) this proposal; while the usefulness of append does come up from time to time, it doesn't come up all that often, at least in my experience.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Vlad from Moscow

unread,
Oct 23, 2013, 8:01:51 AM10/23/13
to std-pr...@isocpp.org
As for me I found out many times when this method would be useful. Even here in the previous message where I showed the difference between insert and append I made a mistake because I had in the head std::basic_string.:) Moreover sometimes I forgot what iterator insert returns. So if you use such a construction as
 
auto it = v.insert( v.end(), std::begin( a ), std::end( a ) );
 
you can make a mistake thinking that the next array will be added to the end of the vector
 
v.insert( it, std::begin( b ), std::end( b ) );
 
On the other hand if you use append there is no such a problem
 
v.append( std::begin( a ), std::end( a ) );
v.append( std::begin( b ), std::end( b ) );
 
This code is very clear opposite to the code with insert.,
 

среда, 23 октября 2013 г., 15:51:32 UTC+4 пользователь Nevin ":-)" Liber написал:

Ville Voutilainen

unread,
Oct 23, 2013, 8:02:59 AM10/23/13
to std-pr...@isocpp.org
On 23 October 2013 14:51, Nevin Liber <ne...@eviloverlord.com> wrote:
I'm pretty much meh (aka neutral to weakly against) this proposal; while the usefulness of append does come up from time to time, it doesn't come up all that often, at least in my experience.


I have found that novices often expect an append() to be available, but cope quite quickly
when told that it's named push_back(). The iterator version is much rarer, as is chaining
or otherwise combining multiple appends. Meh, indeed. I'll stay well out of the room if
LEWG wishes to discuss this. :)

Zhihao Yuan

unread,
Oct 23, 2013, 11:04:07 AM10/23/13
to std-pr...@isocpp.org
On Wed, Oct 23, 2013 at 8:02 AM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> I have found that novices often expect an append() to be available, but cope
> quite quickly
> when told that it's named push_back().

Interestingly in Python `push_back` is named `append`, and
"bulk insertion at the end" is named `extend` :)

> The iterator version is much rarer,
> as is chaining
> or otherwise combining multiple appends.

If it takes a Range, like Python's `extend`, which takes an
iterable object, that would be more useful, I think :)

I always uses string .append() line by line; chained side-
effects are unnecessary and confusing to me.

> Meh, indeed. I'll stay well out of
> the room if
> LEWG wishes to discuss this. :)

lol

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/

Vlad from Moscow

unread,
Oct 23, 2013, 12:20:43 PM10/23/13
to std-pr...@isocpp.org
append shows more clear the intention of the programmer. Consider code
 
v.insert( it, std::begin( a ), std:;end( a ) );
 
You can say nothing whether the array is indeed inserted or appended.
 
Word insert only confuses readers because literally insert and append have different meaning.
 
So in my opinion all sequantial containers with method push_back should have the following set of methods:
 
assign
insert
append
erase
 
and all these methods shall have the following parameters
 
size_type n, const T &value;
InputIterator first, InputIterator last
initializer_list<value_type>
 
in this case they will be interchangeable with clear semantic of their methods.
.
 

среда, 23 октября 2013 г., 19:04:07 UTC+4 пользователь Zhihao Yuan написал:

Nevin Liber

unread,
Oct 23, 2013, 6:08:10 PM10/23/13
to std-pr...@isocpp.org
On 23 October 2013 12:20, Vlad from Moscow <vlad....@mail.ru> wrote:
append shows more clear the intention of the programmer. Consider code
 
v.insert( it, std::begin( a ), std:;end( a ) );
 
You can say nothing whether the array is indeed inserted or appended.

Well, they are using an iterator in a variable, so most likely they have found the position they which to insert the elements of a, regardless of whether it is technically appending or inserting somewhere else.  After all, if they really meant appending, why not write it instead as v.insert(v.end(), std::begin(a), std::end(a));?

Contrived situations don't sway me.  Bad programmers will write convoluted code no matter how many member functions we give them.

Zhihao Yuan

unread,
Oct 23, 2013, 6:31:37 PM10/23/13
to std-pr...@isocpp.org

On Oct 23, 2013 6:09 PM, "Nevin Liber" <ne...@eviloverlord.com> wrote:
> Contrived situations don't sway me.  Bad programmers will write convoluted code no matter how many member functions we give them.

Hehe…

I think we'd better not to regard this as merely a syntax sugar.  I looked at libc++ code and I found that since the position is known to be end(), append() can be implemented in a much simpler way compared with insert().  Not sure how beneficial it is though, but so far it looks not too useless.

Vlad from Moscow

unread,
Oct 23, 2013, 6:41:46 PM10/23/13
to std-pr...@isocpp.org
In my opinion the iterator shall be absent as a whole because appending does not require the iterator. It is an useless and superfluous information. it only provokes potential errors and makes it difficult to read code because every time when you meet method insert you should investigate what it does whether it indeed inserts or it appends or a programmer made an error and forgot substitute end() for some other iterator when he was changing the code.
 
 
 

четверг, 24 октября 2013 г., 2:08:10 UTC+4 пользователь Nevin ":-)" Liber написал:

Zhihao Yuan

unread,
Oct 23, 2013, 6:52:13 PM10/23/13
to std-pr...@isocpp.org

On Oct 23, 2013 6:31 PM, "Zhihao Yuan" <z...@miator.net> wrote:
> I think we'd better not to regard this as merely a syntax sugar.  I looked at libc++ code and I found that since the position is known to be end(), append() can be implemented in a much simpler way compared with insert().  Not sure how beneficial it is though, but so far it looks not too useless.

PS: If you agree with this rationale, I would suggest to add prepend() method to deque, list, and forward_list as well.

Vlad from Moscow

unread,
Oct 23, 2013, 7:05:06 PM10/23/13
to std-pr...@isocpp.org
In fact there is nothing new with the method append because it already exists for std::basic_string. If somebody has some doubts then I advise to try do not use append with std::basic string and substitute it everywhere in code for insert. I am sure that through a month of such coding he will quickly understand that method append is necessary.
 
Introducing method append just makes the common interface of sequential containers more consistent.

четверг, 24 октября 2013 г., 2:52:13 UTC+4 пользователь Zhihao Yuan написал:

Billy O'Neal

unread,
Oct 23, 2013, 7:07:04 PM10/23/13
to std-proposals
Again, append makes sense for basic_string because it corresponds to basic_string's operator+=. That operation doesn't necessarily make sense for all containers.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


--

Vlad from Moscow

unread,
Oct 23, 2013, 7:32:45 PM10/23/13
to std-pr...@isocpp.org
Billy, I do not think that append flows out of operator +=. It looks like that operator += flows out of append.:)
 
To demonstrate that append looks much better than insert I will show the following assignment.
 Let;s assume that there is a vector v1 and you need to copy  its elements in another vector v2 excluding some range that specified by a pair of iterators. For example one iterator points the first negative value of the vector and the second iterator points the last negative value of the vector. The simplest way to do the assignment is to write
 
std::vector<int> v2( v1.begin(), range.first );
v2.append( std::next( range.second ), v1.end() );
 
That is at first the part of the original vector before the first iterator was copied and then the tail of the original vector  was appended.. The code looks very logically and clearly due to using of append.
 
 
 

четверг, 24 октября 2013 г., 3:07:04 UTC+4 пользователь Billy O'Neal написал:

Billy O'Neal

unread,
Oct 23, 2013, 7:51:46 PM10/23/13
to std-proposals
And yet, is no less clearly expressed as:
std::vector<int> v2( v1.begin(), range.first );
append( v2, std::next( range.second ), v1.end() );

which you can already do today without needing a standard modification.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 23, 2013, 7:57:48 PM10/23/13
to std-pr...@isocpp.org
In my personal opinion there is two problems. It is not clear what is the return type of append. And such record can confuse users because they will think that they can use any container because the function iis a general non-member function.

четверг, 24 октября 2013 г., 3:51:46 UTC+4 пользователь Billy O'Neal написал:

Vlad from Moscow

unread,
Oct 23, 2013, 7:59:47 PM10/23/13
to std-pr...@isocpp.org
They will think so by analogy with other similar general functions as for example advance that can be used with any type of iterators (except output iterators).

четверг, 24 октября 2013 г., 3:57:48 UTC+4 пользователь Vlad from Moscow написал:

Zhihao Yuan

unread,
Oct 23, 2013, 8:10:28 PM10/23/13
to std-pr...@isocpp.org
On Wed, Oct 23, 2013 at 7:05 PM, Vlad from Moscow <vlad....@mail.ru> wrote:
> In fact there is nothing new with the method append because it already
> exists for std::basic_string. If somebody has some doubts then I advise to
> try do not use append with std::basic string and substitute it everywhere in
> code for insert. I am sure that through a month of such coding he will
> quickly understand that method append is necessary.
>
> Introducing method append just makes the common interface of sequential
> containers more consistent.

I would say please forget about basic_string. basic_string
is not a general purpose container, so there is minimal reason
to say "more consistent". Containers and string are different.
For example, string's insert() methods returns string&, do you
want containers' insert() also return container&? Leave different
things different.

So far I understand append() as "bulk push_back", so I suggested
to have a "bulk push_front" as well, both as simplified interfaces
to insert(). Now I think it would be more clear if we name append()
`extend_back`, and prepend() `extend_front`. Just keep away from
string's append(), which even can take a pointer to char -- don't tell
me you want to take T* as well.

Evgeny Panasyuk

unread,
Oct 23, 2013, 8:10:43 PM10/23/13
to std-pr...@isocpp.org
They will think so by analogy with other similar general functions as for example advance that can be used with any type of iterators (except output iterators).

Generic function does not imply that it should work for everything.

std::lower_bound does not work for input iterators.

std::sort works only for random access.

 

Billy O'Neal

unread,
Oct 23, 2013, 8:10:55 PM10/23/13
to std-proposals
>It is not clear what is the return type of append.
By that standard, the return type of append here isn't clear either:
v2.append( std::next( range.second ), v1.end() );

Member-ness or nonmember-ness doesn't tell the caller *anything* about the return type.

>can confuse users because they will think that they can use any container because the function iis a general non-member function

By that metric, any STL algorithm that requires bidirectional iterators wouldn't be allowed, because they don't work with input iterators. In fact, advance would be a great *counter example* to your claim, because it isn't obvious why std::advance(std::istream_iterator( ... ), -2) wouldn't work.

Users are expected to understand the function they are calling before calling it.

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 23, 2013, 8:16:38 PM10/23/13
to std-pr...@isocpp.org
It is a bad analogy. Algorithm are some sort of tasks that have usually preconditions. You can not for example use binary_search with non-ordered sequenses. So lower_bound is not a general function as you think. It is very specific function.
 

четверг, 24 октября 2013 г., 4:10:43 UTC+4 пользователь Evgeny Panasyuk написал:

Vlad from Moscow

unread,
Oct 23, 2013, 8:20:01 PM10/23/13
to std-pr...@isocpp.org
In my opinion it is a bad analogy with algorithms. Algorithms are special functions that have preconditions.

четверг, 24 октября 2013 г., 4:10:55 UTC+4 пользователь Billy O'Neal написал:

Billy O'Neal

unread,
Oct 23, 2013, 8:35:47 PM10/23/13
to std-proposals
Erm, I didn't bring up algorithms, you did. (Your example was std::advance) And there's nothing special about them. All functions have preconditions. You can take any old C API and show preconditions. For example:
 
std::string s;
std::abs(s); // Compiler error
 
Append is no different.
 
More to the point, even the member append on basic_string has preconditions. For instance, in the overload of append taking an iterator range, the preconditions are that the parameters are in fact an iterator range. Which comes with all sorts of implied conditions which can't be checked at compile time. (E.g. the iterators must point to the same source range)

Billy O'Neal
Malware Response Instructor - BleepingComputer.com


Vlad from Moscow

unread,
Oct 24, 2013, 4:16:15 AM10/24/13
to std-pr...@isocpp.org
To make function append a non-member function in my opinion  is simply a bad idea.
In fact in this case inside the function you will call method insert because there is no other possibility in this design. So it is not effective. Moreover this design only confuses users because you must list those containers that can be used with this function. I understand that it can be a new silly question in interview: list the containers that can be used with this function and with that frunction.
 It is a very poor design. And when methods will be chained together it will lagain look badly: a mix of member and non-member functions.
I

четверг, 24 октября 2013 г., 4:35:47 UTC+4 пользователь Billy O'Neal написал:

Vlad from Moscow

unread,
Oct 24, 2013, 6:38:15 AM10/24/13
to std-pr...@isocpp.org

четверг, 24 октября 2013 г., 4:10:28 UTC+4 пользователь Zhihao Yuan написал:
On Wed, Oct 23, 2013 at 7:05 PM, Vlad from Moscow <vlad....@mail.ru> wrote:
> In fact there is nothing new with the method append because it already
> exists for std::basic_string. If somebody has some doubts then I advise to
> try do not use append with std::basic string and substitute it everywhere in
> code for insert. I am sure that through a month of such coding he will
> quickly understand that method append is necessary.
>
> Introducing method append just makes the common interface of sequential
> containers more consistent.

I would say please forget about basic_string.  basic_string
is not a general purpose container, so there is minimal reason
to say "more consistent".  Containers and string are different.
I can not agree with you. To have a common interface for all sequential containers is a good idea. std::basic_string has method push_back and method append so I do not see any reason to forget about basic_string.:)
 
 
For example, string's insert() methods returns string&, do you
want containers' insert() also return container&?  Leave different
things different.

But method append will return reference to the container itself. And std::basic_string has the same behaviour for append.
 
So far I understand append() as "bulk push_back", so I suggested
to have a "bulk push_front" as well, both as simplified interfaces
to insert().  Now I think it would be more clear if we name append()
`extend_back`, and prepend() `extend_front`.  Just keep away from
string's append(), which even can take a pointer to char -- don't tell
me you want to take T* as well.

 
As for the prepand then in fact it is insert method because elements of the container logically or physically are shifted left. So opposite to append there is no the same greate sense to introduce prepand. 

Evgeny Panasyuk

unread,
Oct 24, 2013, 8:50:42 AM10/24/13
to std-pr...@isocpp.org
To make function append a non-member function in my opinion  is simply a bad idea.
In fact in this case inside the function you will call method insert because there is no other possibility in this design. So it is not effective.

About which possibility you are talking? Non-member function can be easily overloaded, providing special version when required.
 
Moreover this design only confuses users because you must list those containers that can be used with this function.

There is no need to list all such containers - there can be many user-defined containers. std::sort works on random access iterators, and it does not list all of them.
Only requirenments/concepts can be listed.
 
I understand that it can be a new silly question in interview: list the containers that can be used with this function and with that frunction.
 It is a very poor design.

That question is literally equal to "list containers which have this and that function".
 

billy...@gmail.com

unread,
Oct 24, 2013, 8:58:26 AM10/24/13
to std-proposals
Obviously, repeating "it will confuse users" is getting you no closer to an approved proposal, considering nobody else has stepped up in favor of the member function.

Sent from a touchscreen. Please excuse the brevity and tpyos.

----- Reply message -----
From: "Vlad from Moscow" <vlad....@mail.ru>
To: <std-pr...@isocpp.org>
Subject: [std-proposals] Re: To add the method append for all sequential containers that have method push_back
Date: Thu, Oct 24, 2013 1:16 AM
To make function append a non-member function in my opinion  is simply a bad idea.
On Wed, Oct 23, 2013 at 4:05 PM, Vlad from Moscow <vlad....@mail.ru> wrote:
In fact there is nothing new with the method append because it already exists for std::basic_string. If somebody has some doubts then I advise to try do not use append with std::basic string and substitute it everywhere in code for insert. I am sure that through a month of such coding he will quickly understand that method append is necessary.
 
Introducing method append just makes the common interface of sequential containers more consistent.

Ville Voutilainen

unread,
Oct 24, 2013, 9:08:20 AM10/24/13
to std-pr...@isocpp.org
On 24 October 2013 15:58, billy...@gmail.com <billy...@gmail.com> wrote:
Obviously, repeating "it will confuse users" is getting you no closer to an approved proposal, considering nobody else has stepped up in favor of the member function.

I should then probably say that I'd prefer a member function to a free function.

Nevin Liber

unread,
Oct 24, 2013, 10:40:05 AM10/24/13
to std-pr...@isocpp.org
On 23 October 2013 18:31, Zhihao Yuan <z...@miator.net> wrote:

I looked at libc++ code and I found that since the position is known to be end(), append() can be implemented in a much simpler way compared with insert().

1.  You still need to implement insert anyway.

2.  I can't imagine it has much benefit.  As far as library optimizations go, an implementor right now can always do the end() check in insert and branch to the simpler code if it is indeed better; a decent optimizer should optimize the branch away when written like v.insert(v.end(), b, e);.  (Note: doing so might be a pessimization for insert in general when it cannot be determined at compile time whether or not the position == end()), due to increased code size.)

I look forward to seeing benchmark numbers for this (if anyone cares enough to generate them, and if they don't, that is telling, too).

Zhihao Yuan

unread,
Oct 24, 2013, 1:10:16 PM10/24/13
to std-pr...@isocpp.org
On Thu, Oct 24, 2013 at 10:40 AM, Nevin Liber <ne...@eviloverlord.com> wrote:
> 1. You still need to implement insert anyway.

But you may not need to instantiate it :)

> 2. I can't imagine it has much benefit. As far as library optimizations
> go, an implementor right now can always do the end() check in insert and
> branch to the simpler code if it is indeed better; a decent optimizer should
> optimize the branch away when written like v.insert(v.end(), b, e);. (Note:
> doing so might be a pessimization for insert in general when it cannot be
> determined at compile time whether or not the position == end()), due to
> increased code size.)

Yes. I observed that insert() is never inlined, so there is no chance to
optimize this case. Branch prediction can save a lot, however.

> I look forward to seeing benchmark numbers for this (if anyone cares enough
> to generate them, and if they don't, that is telling, too).

I wrote a crappy patch to implement some vector `extend_back` in
libc++, and benchmarked the forward iterator version with 10000000
times self append 15 items (int) in the front.

Debug mode:

v.insert(end(v), begin(v), begin(v) + 15); 8.0s
v.extend_back(begin(v), begin(v) + 15); 7.6s

-O3

v.insert(end(v), begin(v), begin(v) + 15); 2.27~2.30s
v.extend_back(begin(v), begin(v) + 15); 2.22~2.26.s

So there is some difference but tiny(?); haven't tried more complex
items.

But the implementation is indeed much simpler than insert().
Patch is at

https://gist.github.com/lichray/302b1489e0731d188c10
Reply all
Reply to author
Forward
0 new messages