basic_string(const T&, const Alloc&) turns moves into copiesSection: 27.4.3.3 [string.cons], 27.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.cons].
View all issues with New status.
Discussion:
This will do a copy not a move:
struct Str : std::string {
Str() = default;
Str(Str&& s) : std::string(std::move(s)) { }
};
Str s;
Str s2(std::move(s));
The problem is that the new C++17 constructor:
basic_string(const T&, const Alloc& = Alloc());
is an exact match, but the basic_string move constructor requires a derived-to-base conversion.
assign(const T&) and operator=(const T&).
We can fix this by constraining those functions with !derived_from<T, basic_string>, so
that the move constructor is the only viable function. Libstdc++ has done something very similar since
2017, but using !is_convertible<const T*, const basic_string*> instead of derived_from.
[2022-01-30; Reflector poll]
Set priority to 3 after reflector poll.
Jonathan to revise P/R to use is_base_of or
is_convertible instead of derived_from.
Proposed resolution:
This wording is relative to N4901.
Modify 27.4.3.3 [string.cons] as indicated:
template<class T> constexpr explicit basic_string(const T& t, const Allocator& a = Allocator());-7- Constraints:
(7.1) —
is_convertible_v<const T&, basic_string_view<charT, traits>>istrueand(7.?) —
derived_from<T, basic_string>isfalseand(7.2) —
is_convertible_v<const T&, const charT*>isfalse.-8- Effects: Creates a variable,
sv, as if bybasic_string_view<charT, traits> sv = t;and then behaves the same asbasic_string(sv.data(), sv.size(), a).[…]
template<class T> constexpr basic_string& operator=(const T& t);-27- Constraints:
(27.1) —
is_convertible_v<const T&, basic_string_view<charT, traits>>istrueand(27.?) —
derived_from<T, basic_string>isfalseand(27.2) —
is_convertible_v<const T&, const charT*>isfalse.-28- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return assign(sv);
Modify 27.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>>istrueand(4.?) —
derived_from<T, basic_string>isfalseand(4.2) —
is_convertible_v<const T&, const charT*>isfalse.-5- Effects: Equivalent to:
basic_string_view<charT, traits> sv = t; return assign(sv.data(), sv.size());