Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/string/basic string/operator+"

From cppreference.com
< cpp‎ | string‎ | basic string
(Created page with "{{cpp/string/basic_string/title | operator+}} {{cpp/string/basic_string/sidebar}} {{ddcl list begin}} {{ddcl list item | num=1 | 1= template<class charT, class traits, class Allo...")
 
m (Synopsis: fmt: rm indents below <template>)
 
(27 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{cpp/string/basic_string/title | operator+}}
+
{{cpp/title|operator+{{small|(std::basic_string)}}}}
{{cpp/string/basic_string/sidebar}}
+
{{cpp/string/basic_string/navbar}}
{{ddcl list begin}}
+
{{dcl begin}}
{{ddcl list item | num=1 | 1=
+
{{dcl header|string}}
template<class charT, class traits, class Allocator>
+
{{dcla|num=1|notes={{mark constexpr since c++20}}|1=
    basic_string<charT,traits,Allocator>
+
template< class CharT, class Traits, class Alloc >
        operator+(const basic_string<charT,traits,Allocator>& lhs,
+
std::basic_string<CharT,Traits,Alloc>
                  const basic_string<charT,traits,Allocator>& rhs);
+
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,
 +
              const std::basic_string<CharT,Traits,Alloc>& rhs );
 
}}
 
}}
{{ddcl list item | num=2 | 1=
+
{{dcl|num=2|notes={{mark constexpr since c++20}}|1=
template<class charT, class traits, class Allocator>
+
template< class CharT, class Traits, class Alloc >
    basic_string<charT,traits,Allocator>
+
std::basic_string<CharT,Traits,Alloc>
        operator+(const charT* lhs,
+
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,
                  const basic_string<charT,traits,Allocator>& rhs);
+
              const CharT* rhs );
 
}}
 
}}
{{ddcl list item | num=3 | 1=
+
{{dcl|num=3|notes={{mark constexpr since c++20}}|1=
template<class charT, class traits, class Allocator>
+
template< class CharT, class Traits, class Alloc >
    basic_string<charT,traits,Allocator>
+
std::basic_string<CharT,Traits,Alloc>
          operator+(charT lhs,
+
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,
                    const basic_string<charT,traits,Allocator>& rhs);
+
              CharT rhs );
 
}}
 
}}
{{ddcl list item | num=4 | 1=
+
{{dcla|num=4|since=c++26|1=
template<class charT, class traits, class Allocator>
+
template< class CharT, class Traits, class Alloc >
    basic_string<charT,traits,Allocator>
+
constexpr std::basic_string<CharT,Traits,Alloc>
        operator+(const basic_string<charT,traits,Allocator>& lhs,
+
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,
                  const charT* rhs);
+
              std::type_identity_t<std::basic_string_view<CharT,Traits>> rhs );
 
}}
 
}}
{{ddcl list item | num=5 | 1=
+
{{dcl|num=5|notes={{mark constexpr since c++20}}|1=
template<class charT, class traits, class Allocator>
+
template< class CharT, class Traits, class Alloc >
    basic_string<charT,traits,Allocator>
+
std::basic_string<CharT,Traits,Alloc>
        operator+(const basic_string<charT,traits,Allocator>& lhs,
+
    operator+( const CharT* lhs,
                  charT rhs);
+
              const std::basic_string<CharT,Traits,Alloc>& rhs );
 
}}
 
}}
{{ddcl list end}}
+
{{dcl|num=6|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( CharT lhs,
 +
              const std::basic_string<CharT,Traits,Alloc>& rhs );
 +
}}
 +
{{dcla|num=7|since=c++26|1=
 +
template< class CharT, class Traits, class Alloc >
 +
constexpr std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::type_identity_t<std::basic_string_view<CharT,Traits>> lhs,
 +
              const std::basic_string<CharT,Traits,Alloc>& rhs );
 +
}}
 +
{{dcla|num=8|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,
 +
              std::basic_string<CharT,Traits,Alloc>&& rhs );
 +
}}
 +
{{dcl|num=9|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,
 +
              const std::basic_string<CharT,Traits,Alloc>& rhs );
 +
}}
 +
{{dcl|num=10|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,
 +
              const CharT* rhs );
 +
}}
 +
{{dcl|num=11|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,
 +
              CharT rhs );
 +
}}
 +
{{dcla|num=12|since=c++26|1=
 +
template< class CharT, class Traits, class Alloc >
 +
constexpr std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,
 +
              std::type_identity_t<std::basic_string_view<CharT,Traits>> rhs );
 +
}}
 +
{{dcl|num=13|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,
 +
              std::basic_string<CharT,Traits,Alloc>&& rhs );
 +
}}
 +
{{dcl|num=14|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( const CharT* lhs,
 +
              std::basic_string<CharT,Traits,Alloc>&& rhs );
 +
}}
 +
{{dcl|num=15|since=c++11|notes={{mark constexpr since c++20}}|1=
 +
template< class CharT, class Traits, class Alloc >
 +
std::basic_string<CharT,Traits,Alloc>
 +
    operator+( CharT lhs,
 +
              std::basic_string<CharT,Traits,Alloc>&& rhs );
 +
}}
 +
{{dcla|num=16|since=c++26|1=
 +
template< class CharT, class Traits, class Alloc >
 +
constexpr std::basic_string<CharT,Traits,Alloc>
 +
    operator+( std::type_identity_t<std::basic_string_view<CharT,Traits>> lhs,
 +
              std::basic_string<CharT,Traits,Alloc>&& rhs );
 +
}}
 +
{{dcl end}}
 +
 
 +
Returns a string containing characters from {{c|lhs}} followed by the characters from {{c|rhs}}. Equivalent to:
 +
 
 +
@1,2@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = lhs; r.append(rhs); return r;}}
 +
@3@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = lhs; r.push_back(rhs); return r;}}
 +
@4@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = lhs; r.append(rhs); return r;}}
 +
@5@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(0, lhs); return r;}}
 +
@6@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(r.begin(), lhs); return r;}}
 +
@7@ {{c|1=std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(0, lhs); return r;}}
 +
@8@ {{c|1=lhs.append(rhs); return std::move(lhs);}} except that both {{c|lhs}} and {{c|rhs}} are left in valid but unspecified states. If {{c|lhs}} and {{c|rhs}} have equal allocators, the implementation can move from either.
 +
@9,10@ {{c|1=lhs.append(rhs); return std::move(lhs);}}
 +
@11@ {{c|1=lhs.push_back(rhs); return std::move(lhs);}}
 +
@12@ {{c|1=lhs.append(rhs); return std::move(lhs);}}
 +
@13,14@ {{c|1=rhs.insert(0, lhs); return std::move(rhs);}}
 +
@15@ {{c|1=rhs.insert(rhs.begin(), lhs); return std::move(rhs);}}
 +
@16@ {{c|1=rhs.insert(0, lhs); return std::move(rhs);}}
 +
 
 +
{{rrev|since=c++11|
 +
The allocator used for the result is:
 +
@1-4@ {{c|std::allocator_traits<Alloc>::select_on_container_copy_construction(lhs.get_allocator())
 +
}}
 +
@5-7@ {{c|std::allocator_traits<Alloc>::select_on_container_copy_construction(rhs.get_allocator())
 +
}}
 +
@8-12@ {{c|lhs.get_allocator()}}
 +
@13-16@ {{c|rhs.get_allocator()}}
 +
 
 +
In other words:
 +
* If one operand is a {{tt|basic_string}} rvalue, its allocator is used.
 +
* Otherwise, {{tt|select_on_container_copy_construction}} is used on the allocator of the lvalue {{tt|basic_string}} operand.
 +
In each case, the left operand is preferred when both are {{tt|basic_string}}s of the same value category.
 +
 
 +
For {{vl|8-16}}, all rvalue {{tt|basic_string}} operands are left in valid but unspecified states.
 +
}}
 +
 
 +
===Parameters===
 +
{{par begin}}
 +
{{par|lhs|string{{rev inl|since=c++26|, string view}}, character, or pointer to the first character in a null-terminated array}}
 +
{{par|rhs|string{{rev inl|since=c++26|, string view}}, character, or pointer to the first character in a null-terminated array}}
 +
{{par end}}
 +
 
 +
===Return value===
 +
A string containing characters from {{c|lhs}} followed by the characters from {{c|rhs}}{{rev inl|since=c++11|, using the allocator determined as above}}.
 +
 
 +
{{rrev|since=c++11|1=
 +
===Notes===
 +
{{tt|operator+}} should be used with great caution when stateful allocators are involved{{rev inl|since=c++17| (such as when {{lc|std::pmr::string}} is used)}}. Prior to {{wg21|P1165R1}}, the allocator used for the result was determined by historical accident and can vary from overload to overload for no apparent reason. Moreover, for {{vl|1-5}}, the allocator propagation behavior varies across major standard library implementations and differs from the behavior depicted in the standard.
 +
 
 +
Because the allocator used by the result of {{tt|operator+}} is sensitive to value category, {{tt|operator+}} is not associative with respect to allocator propagation:
 +
 
 +
{{source|1=
 +
using my_string = std::basic_string<char, std::char_traits<char>, my_allocator<char>>;
 +
my_string cat();
 +
const my_string& dog();
 +
 
 +
my_string meow = /* ... */, woof = /* ... */;
 +
meow + cat() + /* ... */; // uses select_on_container_copy_construction on meow's allocator
 +
woof + dog() + /* ... */; // uses allocator of dog()'s return value instead
 +
 
 +
meow + woof + meow; // uses select_on_container_copy_construction on meow's allocator
 +
meow + (woof + meow); // uses SOCCC on woof's allocator instead
 +
}}
 +
 
 +
For a chain of {{tt|operator+}} invocations, the allocator used for the ultimate result may be controlled by prepending an rvalue {{tt|basic_string}} with the desired allocator:
 +
 
 +
{{source|1=
 +
// use my_favorite_allocator for the final result
 +
my_string(my_favorite_allocator) + meow + woof + cat() + dog();
 +
}}
 +
 
 +
For better and portable control over allocators, member functions like {{rlpt|append}}, {{rlpt|insert}}, and {{rlpt|1=operator+=}} should be used on a result string constructed with the desired allocator.
 +
}}
 +
 
 +
{{rrev|since=c++26|1=
 +
The usage of {{c/core|std::type_identity_t}} as parameter in overloads {{vl|4}}, {{vl|7}}, {{vl|12}}, and {{vl|16}} ensures that an object of type {{c/core|std::basic_string<CharT, Traits, Allocator>}} can always be concatenated to an object of a type {{tt|T}} with an implicit conversion to {{c/core|std::basic_string_view<CharT, Traits>}}, and vice versa, as per [[cpp/language/overload_resolution#Call to an overloaded operator|overload resolution]] rules<!--[over.match.oper]-->.
 +
 
 +
{{ftm begin}}
 +
{{ftm|__cpp_lib_string_view|std=C++26|value=202403|Concatenation of strings and string views, overloads {{vl|4}}, {{vl|7}}, {{vl|12}}, {{vl|16}}}}
 +
{{ftm end}}
 +
}}
 +
 
 +
===Example===
 +
{{example
 +
|code=
 +
#include <iostream>
 +
#include <string>
 +
#include <string_view>
 +
 
 +
int main()
 +
{
 +
    std::string s1 = "Hello";
 +
    std::string s2 = "world";
 +
    const char* end = "!\n";
 +
    std::cout << s1 + ' ' + s2 + end;
 +
 
 +
    std::string_view water{" Water"};
 +
    #if __cpp_lib_string_view >= 202403
 +
    std::cout << s1 + water + s2 << end; // overload (4), then (1)
 +
    #else
 +
    std::cout << s1 + std::string(water) + s2 << end; // OK, but less efficient
 +
    #endif
 +
}
 +
|output=
 +
Hello world!
 +
Hello Waterworld!
 +
}}
 +
 
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|paper=P1165R1|std=C++11|before=allocator propagation is haphazard and inconsistent|after=made more consistent}}
 +
{{dr list end}}
  
Returns a string containing characters from both operands
+
===See also===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/string/basic_string/dsc operator+{{=}}}}
 +
{{dsc inc|cpp/string/basic_string/dsc append}}
 +
{{dsc inc|cpp/string/basic_string/dsc insert}}
 +
{{dsc end}}
  
{{todo}}
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 16:26, 12 May 2024

 
 
 
std::basic_string
Member functions
Element access
Iterators
Capacity
Modifiers
Search
Operations
Constants
Non-member functions
operator+
I/O
Comparison
(until C++20)(until C++20)(until C++20)(until C++20)(until C++20)(C++20)
Numeric conversions
(C++11)(C++11)(C++11)
(C++11)(C++11)
(C++11)(C++11)(C++11)
(C++11)
(C++11)
Literals
Helper classes
Deduction guides (C++17)

 
Defined in header <string>
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,

               const std::basic_string<CharT,Traits,Alloc>& rhs );
(1) (constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,

               const CharT* rhs );
(2) (constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,

               CharT rhs );
(3) (constexpr since C++20)
template< class CharT, class Traits, class Alloc >

constexpr std::basic_string<CharT,Traits,Alloc>
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,

               std::type_identity_t<std::basic_string_view<CharT,Traits>> rhs );
(4) (since C++26)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const CharT* lhs,

               const std::basic_string<CharT,Traits,Alloc>& rhs );
(5) (constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( CharT lhs,

               const std::basic_string<CharT,Traits,Alloc>& rhs );
(6) (constexpr since C++20)
template< class CharT, class Traits, class Alloc >

constexpr std::basic_string<CharT,Traits,Alloc>
    operator+( std::type_identity_t<std::basic_string_view<CharT,Traits>> lhs,

               const std::basic_string<CharT,Traits,Alloc>& rhs );
(7) (since C++26)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,

               std::basic_string<CharT,Traits,Alloc>&& rhs );
(8) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,

               const std::basic_string<CharT,Traits,Alloc>& rhs );
(9) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,

               const CharT* rhs );
(10) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,

               CharT rhs );
(11) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

constexpr std::basic_string<CharT,Traits,Alloc>
    operator+( std::basic_string<CharT,Traits,Alloc>&& lhs,

               std::type_identity_t<std::basic_string_view<CharT,Traits>> rhs );
(12) (since C++26)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const std::basic_string<CharT,Traits,Alloc>& lhs,

               std::basic_string<CharT,Traits,Alloc>&& rhs );
(13) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( const CharT* lhs,

               std::basic_string<CharT,Traits,Alloc>&& rhs );
(14) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

std::basic_string<CharT,Traits,Alloc>
    operator+( CharT lhs,

               std::basic_string<CharT,Traits,Alloc>&& rhs );
(15) (since C++11)
(constexpr since C++20)
template< class CharT, class Traits, class Alloc >

constexpr std::basic_string<CharT,Traits,Alloc>
    operator+( std::type_identity_t<std::basic_string_view<CharT,Traits>> lhs,

               std::basic_string<CharT,Traits,Alloc>&& rhs );
(16) (since C++26)

Returns a string containing characters from lhs followed by the characters from rhs. Equivalent to:

1,2) std::basic_string<CharT, Traits, Allocator> r = lhs; r.append(rhs); return r;
3) std::basic_string<CharT, Traits, Allocator> r = lhs; r.push_back(rhs); return r;
4) std::basic_string<CharT, Traits, Allocator> r = lhs; r.append(rhs); return r;
5) std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(0, lhs); return r;
6) std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(r.begin(), lhs); return r;
7) std::basic_string<CharT, Traits, Allocator> r = rhs; r.insert(0, lhs); return r;
8) lhs.append(rhs); return std::move(lhs); except that both lhs and rhs are left in valid but unspecified states. If lhs and rhs have equal allocators, the implementation can move from either.
9,10) lhs.append(rhs); return std::move(lhs);
11) lhs.push_back(rhs); return std::move(lhs);
12) lhs.append(rhs); return std::move(lhs);
13,14) rhs.insert(0, lhs); return std::move(rhs);
15) rhs.insert(rhs.begin(), lhs); return std::move(rhs);
16) rhs.insert(0, lhs); return std::move(rhs);

The allocator used for the result is:

1-4) std::allocator_traits<Alloc>::select_on_container_copy_construction(lhs.get_allocator())
5-7) std::allocator_traits<Alloc>::select_on_container_copy_construction(rhs.get_allocator())
8-12) lhs.get_allocator()
13-16) rhs.get_allocator()

In other words:

  • If one operand is a basic_string rvalue, its allocator is used.
  • Otherwise, select_on_container_copy_construction is used on the allocator of the lvalue basic_string operand.

In each case, the left operand is preferred when both are basic_strings of the same value category.

For (8-16), all rvalue basic_string operands are left in valid but unspecified states.

(since C++11)

Contents

[edit] Parameters

lhs - string, string view(since C++26), character, or pointer to the first character in a null-terminated array
rhs - string, string view(since C++26), character, or pointer to the first character in a null-terminated array

[edit] Return value

A string containing characters from lhs followed by the characters from rhs, using the allocator determined as above(since C++11).

Notes

operator+ should be used with great caution when stateful allocators are involved (such as when std::pmr::string is used)(since C++17). Prior to P1165R1, the allocator used for the result was determined by historical accident and can vary from overload to overload for no apparent reason. Moreover, for (1-5), the allocator propagation behavior varies across major standard library implementations and differs from the behavior depicted in the standard.

Because the allocator used by the result of operator+ is sensitive to value category, operator+ is not associative with respect to allocator propagation:

using my_string = std::basic_string<char, std::char_traits<char>, my_allocator<char>>;
my_string cat();
const my_string& dog();
 
my_string meow = /* ... */, woof = /* ... */;
meow + cat() + /* ... */; // uses select_on_container_copy_construction on meow's allocator
woof + dog() + /* ... */; // uses allocator of dog()'s return value instead
 
meow + woof + meow; // uses select_on_container_copy_construction on meow's allocator
meow + (woof + meow); // uses SOCCC on woof's allocator instead

For a chain of operator+ invocations, the allocator used for the ultimate result may be controlled by prepending an rvalue basic_string with the desired allocator:

// use my_favorite_allocator for the final result
my_string(my_favorite_allocator) + meow + woof + cat() + dog();

For better and portable control over allocators, member functions like append, insert, and operator+= should be used on a result string constructed with the desired allocator.

(since C++11)

The usage of std::type_identity_t as parameter in overloads (4), (7), (12), and (16) ensures that an object of type std::basic_string<CharT, Traits, Allocator> can always be concatenated to an object of a type T with an implicit conversion to std::basic_string_view<CharT, Traits>, and vice versa, as per overload resolution rules.

Feature-test macro Value Std Feature
__cpp_lib_string_view 202403 (C++26) Concatenation of strings and string views, overloads (4), (7), (12), (16)
(since C++26)

[edit] Example

#include <iostream>
#include <string>
#include <string_view>
 
int main()
{
    std::string s1 = "Hello";
    std::string s2 = "world";
    const char* end = "!\n";
    std::cout << s1 + ' ' + s2 + end;
 
    std::string_view water{" Water"};
    #if __cpp_lib_string_view >= 202403
    std::cout << s1 + water + s2 << end; // overload (4), then (1)
    #else
    std::cout << s1 + std::string(water) + s2 << end; // OK, but less efficient
    #endif
}

Output:

Hello world!
Hello Waterworld!

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
P1165R1 C++11 allocator propagation is haphazard and inconsistent made more consistent

[edit] See also

appends characters to the end
(public member function) [edit]
appends characters to the end
(public member function) [edit]
inserts characters
(public member function) [edit]