Created on 2016-07-30.00:00:00 last changed 90 months ago
Proposed resolution:
This wording is relative to N4606.
In [basic.string] modify the synopsis for basic_string as follows:
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { public: […] template<class T> basic_string& append(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos); […] template<class T> basic_string& assign(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos); […] template<class T> basic_string& insert(size_type pos1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n = npos); […] template<class T> basic_string& replace(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos); […] template<class T> int compare(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos) const; […] }; }
In [string.append], modify basic_string_view overload as follows:
template<class T> basic_string& append(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos);-7- Throws: out_of_range if pos > sv.size().
-8- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to append as the smaller of n and sv.size() - pos and calls append(sv.data() + pos, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false. -9- Returns: *this.
In [string.assign], modify basic_string_view overload as follows:
template<class T> basic_string& assign(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos);-9- Throws: out_of_range if pos > sv.size().
-10- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to assign as the smaller of n and sv.size() - pos and calls assign(sv.data() + pos, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false. -11- Returns: *this.
In [string.insert], modify basic_string_view overload as follows:
template<class T> basic_string& insert(size_type pos1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > sv.size().
-7- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to assign as the smaller of n and sv.size() - pos2 and calls insert(pos1, sv.data() + pos2, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false. -8- Returns: *this.
In [string.replace], modify basic_string_view overload as follows:
template<class T> basic_string& replace(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > sv.size().
-7- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to be inserted as the smaller of n2 and sv.size() - pos2 and calls replace(pos1, n1, sv.data() + pos2, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false. -8- Returns: *this.
In [string.compare], modify basic_string_view overload as follows:
[Drafting note: The wording changes below are for the same part of the standard as 2771. However, they do not conflict. This one changes the definition of the routine, while the other changes the "Effects". — end drafting note]
template<class T> int compare(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos) const;-4- Effects: Equivalent to:
{ basic_string_view<charT, traits> sv = t; return basic_string_view<charT, traits>(this.data(), pos1, n1).compare(sv, pos2, n2); }-?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false.
[ 2016-10 Telecon ]
Ville's wording has been implemented in libstdc++ and libc++. Move this to Tentatively Ready and 2757 to Tentatively Resolved
Previous resolution [SUPERSEDED]:
This wording is relative to N4606.
In [basic.string] modify the synopsis for basic_string as follows:
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { public: […] template<class T> basic_string& append(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos); […] template<class T> basic_string& assign(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos); […] template<class T> basic_string& insert(size_type pos1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n = npos); […] template<class T> basic_string& replace(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos); […] template<class T> int compare(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos) const; […] }; }In [string.append], modify basic_string_view overload as follows:
template<class T> basic_string& append(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos);-7- Throws: out_of_range if pos > sv.size().
-8- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to append as the smaller of n and sv.size() - pos and calls append(sv.data() + pos, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true. -9- Returns: *this.In [string.assign], modify basic_string_view overload as follows:
template<class T> basic_string& assign(basic_string_view<charT, traits> svconst T& t, size_type pos, size_type n = npos);-9- Throws: out_of_range if pos > sv.size().
-10- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to assign as the smaller of n and sv.size() - pos and calls assign(sv.data() + pos, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true. -11- Returns: *this.In [string.insert], modify basic_string_view overload as follows:
template<class T> basic_string& insert(size_type pos1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > sv.size().
-7- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to assign as the smaller of n and sv.size() - pos2 and calls insert(pos1, sv.data() + pos2, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true. -8- Returns: *this.In [string.replace], modify basic_string_view overload as follows:
template<class T> basic_string& replace(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > sv.size().
-7- Effects: Creates a variable, sv, as if by basic_string_view<charT, traits> sv = t. Determines the effective length rlen of the string to be inserted as the smaller of n2 and sv.size() - pos2 and calls replace(pos1, n1, sv.data() + pos2, rlen). -?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true. -8- Returns: *this.In [string.compare], modify basic_string_view overload as follows:
template<class T> int compare(size_type pos1, size_type n1,basic_string_view<charT, traits> svconst T& t, size_type pos2, size_type n2 = npos) const;-4- Effects: Equivalent to:
{ basic_string_view<charT, traits> sv = t; return basic_string_view<charT, traits>(this.data(), pos1, n1).compare(sv, pos2, n2); }-?- Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true.
[ 2016-10-05 ]
Ville provides revised wording.
[ 2016-09-09 Issues Resolution Telecon ]
Ville to provide updated wording; Marshall to implement
[ 2016-08-16, Jonathan Wakely reopens ]
The P/R is not correct, the new overloads get chosen in preference to the overloads taking const char* when passed a char*:
#include <string> int main () { std::string str("a"); char c = 'b'; str.replace(0, 1, &c, 1); if (str[0] != 'b') __builtin_abort(); }
With the resolution of 2758 this is now equivalent to:
str.replace(0, 1, string_view{&c, 1}, 1);
which replaces the character with string_view{"b", 1}.substr(1, npos) i.e. an empty string.
The SFINAE constraints need to disable the new overloads for (at least) the case of non-const value_type* arguments. I've implemented an alternative resolution, which would be specified as:Remarks: This function shall not participate in overload resolution unless is_convertible_v<const T&, basic_string_view<charT, traits>> is true and is_convertible_v<const T&, const charT*> is false.
All the overloads have the same problem.
This program prints no output in C++14, and we should make sure it prints no output in C++17 too:#include <string> int main() { std::string str("a"); char c[1] = { 'b' }; str.append(c, 1); if (str != "ab") puts("bad append"); str.assign(c, 1); if (str != "b") puts("bad assign"); str.insert(0, c, 1); if (str != "bb") puts("bad insert"); str.replace(0, 2, c, 1); if (str != "b") puts("bad replace"); if (str.compare(0, 1, c, 1)) puts("bad compare"); }
Ville and I considered "is_same_v<decay_t<T>, char*> is false" but that would still select the wrong overload for an array of const char, because the new function template would be preferred to doing an array-to-pointer conversion to call the old overload.
[ 2016-08, Chicago ]
Fri PM: Move to Tentatively Ready
[ 2016-08-05, Chicago LWG ]
Given feedback from discussion, we wish to go with the is_convertible_v method, but change:
[ 2016-08-05, Tim Song comments ]
On the assumption that the basic_string version is untouchable, I like the updated P/R, with a couple comments:
If it's constraining on is_convertible to basic_string_view, then I think it should take by reference to avoid copying T, which can be arbitrarily expensive. Both const T& and T&& should work; the question is whether to accommodate non-const operator basic_string_view()s (which arguably shouldn't exist).
Minor issue: compare tests is_convertible and then uses direct-initialization syntax (which is is_constructible). They should match, because it's possible to have basic_string_view sv = t; succeed yet basic_string_view sv(t); fail.
[ 2016-08-03, Chicago, Robert Douglas provides wording ]
Before C++17, we had the following signature to std::basic_string:
basic_string& assign(const basic_string& str, size_type pos, size_type n = npos);
Unlike most of the other member functions on std::basic_string, there were not corresponding versions that take a charT* or (charT *, size).
In p0254r2, we (I) added:basic_string& assign(basic_string_view<charT, traits> sv, size_type pos, size_type n = npos);
which made the code above ambiguous. There are two conversions from "const charT*", one to basic_string, and the other to basic_string_view, and they're both equally good (in the view of the compiler).
This ambiguity also occurs with the callsinsert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); insert(size_type pos1, basic_string_view<charT, traits> sv, size_type pos2, size_type n = npos);
but I will file a separate issue (2757) for that.
A solution is to add even more overloads to assign, to make it match all the other member functions of basic_string, which come in fours (string, pointer, pointer + size, string_view).History | |||
---|---|---|---|
Date | User | Action | Args |
2017-07-30 20:15:43 | admin | set | status: wp -> c++17 |
2016-11-14 03:59:28 | admin | set | status: pending -> wp |
2016-11-14 03:55:22 | admin | set | status: ready -> pending |
2016-10-10 20:46:47 | admin | set | messages: + msg8553 |
2016-10-10 20:46:47 | admin | set | status: open -> ready |
2016-10-05 20:46:04 | admin | set | messages: + msg8537 |
2016-09-12 04:46:33 | admin | set | messages: + msg8519 |
2016-09-04 17:31:27 | admin | set | messages: + msg8489 |
2016-09-04 17:31:27 | admin | set | status: ready -> open |
2016-08-06 21:12:20 | admin | set | messages: + msg8450 |
2016-08-06 21:12:20 | admin | set | status: new -> ready |
2016-08-05 21:58:58 | admin | set | messages: + msg8433 |
2016-08-05 17:55:05 | admin | set | messages: + msg8428 |
2016-08-04 18:16:06 | admin | set | messages: + msg8396 |
2016-08-04 18:16:06 | admin | set | messages: + msg8395 |
2016-07-30 00:00:00 | admin | create |