Currently, the following, reasonable expressions are ill-formed
"string"s + "_view"sv
"string"sv + "_view"s
even though you can use
std::string's
operator+= and
append member functions if the rhs is a
std::string_view.
I would like to propose the introduction of the
std::string::operator+ overloads that would make such expressions well-formed. This would make the interface consistent, and prevent having to do less intuitive work-arounds to get equivalent effects:
auto sv {"C++17"sv};
auto str1 {std::string{sv} + " today"s}; // explicit conversion
auto str2 {"Today: "s += sv}; // why not +?
auto str3 {("Today: "s += sv) + ", tomorrow: "s += sv}; // messy
I had submitted a LWG issue on this. Here, I quote part of the reply by Daniel Krügler.
The second point is whether this is actually a feature request, not a
library defect. The design of basic_string_view intentionally did
support comparison, but not concatenations. This is obviously
evolution material, so I would strongly recommend to write a proposal
for this.
I tried hunting down why there's no
operator+, and
only found this in N3512:
I also omitted operator+(basic_string, basic_string_ref) because LLVM returns a lightweight object from this overload and only performs the concatenation lazily. If we define this overload, we'll have a hard time introducing that lightweight concatenation later.
I can't believe that would be the only reason.
Here's the proposed wording included in my non-accepted issue.
Proposed wording:This wording is relative to N4606.
Modify [string.classes]:
...
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string<charT, traits, Allocator>&& lhs,
basic_string<charT, traits, Allocator>&& rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string_view<charT, traits> lhs,
const basic_string<charT, traits, Allocator>& rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string_view<charT, traits> lhs,
basic_string<charT, traits, Allocator>&& rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(const charT* lhs,
const basic_string<charT, traits, Allocator>& rhs);
...
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(charT lhs, basic_string<charT, traits, Allocator>&& rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(const basic_string<charT, traits, Allocator>& lhs,
basic_string_view<charT, traits> rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string<charT, traits, Allocator>&& lhs,
basic_string_view<charT, traits> rhs);
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(const basic_string<charT, traits, Allocator>& lhs,
const charT* rhs);
...
Add after [string::op+]/4:
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string_view<charT, traits> lhs,
const basic_string<charT, traits, Allocator>& rhs); Returns:
basic_string<charT, traits, Allocator>(lhs) + rhs.
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string_view<charT, traits> lhs,
basic_string<charT, traits, Allocator>&& rhs); Returns:
std::move(rhs.insert(0, lhs)).
Add after [string::op+]/10:
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(const basic_string<charT, traits, Allocator>& lhs,
basic_string_view<charT, traits> rhs); Returns:
lhs + basic_string<charT, traits, Allocator>(rhs).
template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(basic_string<charT, traits, Allocator>&& lhs,
basic_string_view<charT, traits> rhs); Returns:
std::move(lhs.insert(rhs)).