assign
of std::basic_string
Section: 27.4.3 [basic.string] Status: C++14 Submitter: Vladimir Grigoriev Opened: 2013-06-26 Last modified: 2016-11-12
Priority: Not Prioritized
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with C++14 status.
Discussion:
Constructors and member functions assign
of class std::basic_string
have one to one relation (except the
explicit constructor that creates an empty string). The following list shows this relation:
explicit basic_string(const Allocator& a = Allocator()); basic_string(const basic_string& str); basic_string& assign(const basic_string& str); basic_string(basic_string&& str) noexcept; basic_string& assign(basic_string&& str) noexcept; basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator()); basic_string& assign(const basic_string& str, size_type pos, size_type n); basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); basic_string& assign(const charT* s, size_type n); basic_string(const charT* s, const Allocator& a = Allocator()); basic_string& assign(const charT* s); basic_string(size_type n, charT c, const Allocator& a = Allocator()); basic_string& assign(size_type n, charT c); template<class InputIterator> basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last); basic_string(initializer_list<charT>, const Allocator& = Allocator()); basic_string& assign(initializer_list<charT>);
So in fact any creating of an object of type std::basic_string
using any of the above constructors
except the explicit constructor can be substituted for creating a (possibly non-empty) string and
then applying to it the corresponding method assign.
std::string s("Hello World");
and
std::string s; s.assign("Hello World");
However there is one exception that has no a logical support. It is the pair of the following constructor and member function
assign
basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator()); basic_string& assign(const basic_string& str, size_type pos, size_type n);
The third parameter of the constructor has a default argument while in the assign
function it is absent. So it is impossible
one to one to substitute the following code snippet
std::string s("Hello World"); std::string t(s, 6);
by
std::string s("Hello World"); std::string t; t.assign(s, 6); // error: no such function
To get an equivalent result using the assign
function the programmer has to complicate the code that is error-prone
std::string s("Hello World"); std::string t; t.assign(s, 6, s.size() - 6);
To fix that, the declaration of the member function assign
should be changed in such a way that its declaration
would be fully compatible with the declaration of the corresponding constructor, that is to specify the same default argument
for the third parameter of the assign
.
The assign
function is not the only function that requires to be revised.
assign
one more member function
append
. We will get:
explicit basic_string(const Allocator& a = Allocator()); basic_string(const basic_string& str); basic_string& assign(const basic_string& str); basic_string& append(const basic_string& str); basic_string(basic_string&& str) noexcept; basic_string& assign(basic_string&& str) noexcept; basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator()); basic_string& assign(const basic_string& str, size_type pos, size_type n); basic_string& append(const basic_string& str, size_type pos, size_type n); basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); basic_string& assign(const charT* s, size_type n); basic_string& append(const charT* s, size_type n); basic_string(const charT* s, const Allocator& a = Allocator()); basic_string& assign(const charT* s); basic_string& append(const charT* s); basic_string(size_type n, charT c, const Allocator& a = Allocator()); basic_string& assign(size_type n, charT c); basic_string& append(size_type n, charT c); template<class InputIterator> basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last); template<class InputIterator> basic_string& append(InputIterator first, InputIterator last); basic_string(initializer_list<charT>, const Allocator& = Allocator()); basic_string& assign(initializer_list<charT>); basic_string& append(initializer_list<charT>);
As it seen from this record:
basic_string(const basic_string& str, size_type pos, size_type n = npos,
const Allocator& a = Allocator());
basic_string& assign(const basic_string& str, size_type pos,
size_type n);
basic_string& append(const basic_string& str, size_type pos,
size_type n);
it is obvious that the function append
also should have the default argument that is that it should be declared as:
basic_string& append(const basic_string& str, size_type pos, size_type n = npos);
In fact there is no a great difference in using assign
or append
especially when the string is empty:
std::string s("Hello World"); std::string t; t.assign(s, 6); std::string s("Hello World"); std::string t; t.append(s, 6);
In both cases the result will be the same. So the assign
and append
will be interchangeable from the point
of view of used arguments.
std::basic_string
that could be brought in conformity with considered above functions.
They are member functions insert
, replace
, and compare
.
So it is suggested to substitute the following declarations of insert
, replace
, and compare
:
basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n); basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2); int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2) const;
by the declarations:
basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos) const;
[2013-09 Chicago]
Howard: Are we positive this won't conflict with any other overloads?
They all appear to be unambiguous. Alisdair: Ok, move to Ready.Proposed resolution:
Change class template basic_string
synopsis, 27.4.3 [basic.string] p5, as indicated:
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string { public: […] basic_string& append(const basic_string& str, size_type pos, size_type n = npos); […] basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); […] basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); […] basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); […] int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos) const; […] }; }
Change 27.4.3.7.2 [string.append] before p3 as indicated:
basic_string& append(const basic_string& str, size_type pos, size_type n = npos);
Change 27.4.3.7.3 [string.assign] before p4 as indicated:
basic_string& assign(const basic_string& str, size_type pos, size_type n = npos);
Change 27.4.3.7.4 [string.insert] before p5 as indicated:
basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos);
Change 27.4.3.7.6 [string.replace] before p5 as indicated:
basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos);
Change 27.4.3.8.4 [string.compare] before p4 as indicated:
int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos) const;