This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 23.4.3.7.2 [string.append], 23.4.3.7.3 [string.assign] Status: New Submitter: Jonathan Wakely Opened: 2022-01-21 Last modified: 2022-01-30
Priority: 3
View all other issues in [string.append].
View all issues with New status.
Discussion:
This will allocate temporary string, then copy one byte from it:
std::string s; s.append("a very very long string that doesn't fit in SSO buffer", 13, 1);
The problem is that there is no overload accepting an NTBS there, so it converts to a temporary string using:
append(const basic_string&, size_t, size_t = npos);
C++17 added a new overload for a string_view:
append(const T&, size_t, size_t = npos);
But that overload is constrained to not allow const char* arguments, so we still create a temporary string.
If we're going to accept those arguments, we should do so efficiently, without forcing an unnecessary allocation. We could do better if we split the append(const T&, ...) overload into:append(const T&, size_t); append(const T&, size_t, size_t);
and then remove the !is_convertible_v<const T&, const charT*> constraint from the second overload (Option A in the proposed resolution).
Alternatively, we can leave the append(const T&, size_t, size_t) overload alone and just add one taking exactly the arguments used above. That seems simpler to me, and I prefer that (Option B in the Proposed Resolution). The same problem applies to assign("...", pos, n).[2022-01-30; Reflector poll]
Set priority to 3 after reflector poll.
Proposed resolution:
This wording is relative to N4901.
[Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]
Option A:
Modify 23.4.3.1 [basic.string.general], class template basic_string synopsis, as indicated:
[…] // 23.4.3.7 [string.modifiers], modifiers […] template<class T> constexpr basic_string& append(const T& t); template<class T> constexpr basic_string& append(const T& t, size_type pos); template<class T> constexpr basic_string& append(const T& t, size_type pos, size_type n= npos); constexpr basic_string& append(const charT* s, size_type n); […] template<class T> constexpr basic_string& assign(const T& t); template<class T> constexpr basic_string& assign(const T& t, size_type pos); template<class T> constexpr basic_string& assign(const T& t, size_type pos, size_type n= npos); constexpr basic_string& assign(const charT* s, size_type n); […]
Modify 23.4.3.7.2 [string.append] as indicated:
template<class T> constexpr basic_string& append(const T& t);-3- Constraints:
(3.1) — is_convertible_v<const T&, basic_string_view<charT, traits>> is true and
(3.2) — is_convertible_v<const T&, const charT*> is false.
-4- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return append(sv.data(), sv.size());template<class T> constexpr basic_string& append(const T& t, size_type pos);-?- Constraints:
(?.1) — is_convertible_v<const T&, basic_string_view<charT, traits>> is true and
(?.2) — is_convertible_v<const T&, const charT*> is false.
-?- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return append(sv.substr(pos));template<class T> constexpr basic_string& append(const T& t, size_type pos, size_type n= npos);-5- Constraints:
(5.1) —is_convertible_v<const T&, basic_string_view<charT, traits>> is trueand
(5.2) — is_convertible_v<const T&, const charT*> is false.-6- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return append(sv.substr(pos, n));
Modify 23.4.3.7.3 [string.assign] as indicated:
template<class T> constexpr basic_string& assign(const T& t);-4- Constraints:
(4.1) — is_convertible_v<const T&, basic_string_view<charT, traits>> is true and
(4.2) — is_convertible_v<const T&, const charT*> is false.
-5- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return assign(sv.data(), sv.size());template<class T> constexpr basic_string& assign(const T& t, size_type pos);-?- Constraints:
(?.1) — is_convertible_v<const T&, basic_string_view<charT, traits>> is true and
(?.2) — is_convertible_v<const T&, const charT*> is false.
-?- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return assign(sv.substr(pos));template<class T> constexpr basic_string& assign(const T& t, size_type pos, size_type n= npos);-6- Constraints:
(6.1) —is_convertible_v<const T&, basic_string_view<charT, traits>> is trueand
(6.2) — is_convertible_v<const T&, const charT*> is false.-7- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return assign(sv.substr(pos, n));
Option B:
Modify 23.4.3.1 [basic.string.general], class template basic_string synopsis, as indicated:
[…] // 23.4.3.7 [string.modifiers], modifiers […] constexpr basic_string& append(const charT* s, size_type n); constexpr basic_string& append(const charT* s); constexpr basic_string& append(const charT* s, size_type pos, size_type n); constexpr basic_string& append(size_type n, charT c); […] constexpr basic_string& assign(const charT* s, size_type n); constexpr basic_string& assign(const charT* s); constexpr basic_string& assign(const charT* s, size_type pos, size_type n); constexpr basic_string& assign(size_type n, charT c); […]
Modify 23.4.3.7.2 [string.append] as indicated:
constexpr basic_string& append(const charT* s, size_type n);-7- Preconditions: [s, s + n) is a valid range.
-8- Effects: Appends a copy of the range [s, s + n) to the string. -9- Returns: *this.constexpr basic_string& append(const charT* s);-10- Effects: Equivalent to: return append(s, traits::length(s));
constexpr basic_string& append(const charT* s, size_type pos, size_type n);-?- Effects: Equivalent to: return append(basic_string_view<charT, traits>(s).substr(pos, n));
Modify 23.4.3.7.3 [string.assign] as indicated:
constexpr basic_string& assign(const charT* s, size_type n);-8- Preconditions: [s, s + n) is a valid range.
-9- Effects: Replaces the string controlled by *this with a copy of the range [s, s + n). -10- Returns: *this.constexpr basic_string& assign(const charT* s);-11- Effects: Equivalent to: return assign(s, traits::length(s));
constexpr basic_string& assign(const charT* s, size_type pos, size_type n);-?- Effects: Equivalent to: return assign(basic_string_view<charT, traits>(s).substr(pos, n));