Defined in header
template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(conststd::basic_string<CharT,Traits,Alloc>&lhs,conststd::basic_string<CharT,Traits,Alloc>&rhs); (1)(constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(conststd::basic_string<CharT,Traits,Alloc>&lhs,constCharT*rhs); (2) (constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(conststd::basic_string<CharT,Traits,Alloc>&lhs,CharTrhs); (3) (constexpr since C++20)template<classCharT,classTraits,classAlloc>constexprstd::basic_string<CharT,Traits,Alloc>operator+(conststd::basic_string<CharT,Traits,Alloc>&lhs,std::type_identity_t<std::basic_string_view<CharT,Traits>>rhs); (4)(since C++26)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(constCharT*lhs,conststd::basic_string<CharT,Traits,Alloc>&rhs); (5) (constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(CharTlhs,conststd::basic_string<CharT,Traits,Alloc>&rhs); (6) (constexpr since C++20)template<classCharT,classTraits,classAlloc>constexprstd::basic_string<CharT,Traits,Alloc>operator+(std::type_identity_t<std::basic_string_view<CharT,Traits>>lhs,conststd::basic_string<CharT,Traits,Alloc>&rhs); (7)(since C++26)template<classCharT,classTraits,classAlloc>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<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(std::basic_string<CharT,Traits,Alloc>&&lhs,conststd::basic_string<CharT,Traits,Alloc>&rhs); (9) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(std::basic_string<CharT,Traits,Alloc>&&lhs,constCharT*rhs); (10) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(std::basic_string<CharT,Traits,Alloc>&&lhs,CharTrhs); (11) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>constexprstd::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<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(conststd::basic_string<CharT,Traits,Alloc>&lhs,std::basic_string<CharT,Traits,Alloc>&&rhs); (13) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(constCharT*lhs,std::basic_string<CharT,Traits,Alloc>&&rhs); (14) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>std::basic_string<CharT,Traits,Alloc>operator+(CharTlhs,std::basic_string<CharT,Traits,Alloc>&&rhs); (15) (since C++11)
(constexpr since C++20)template<classCharT,classTraits,classAlloc>constexprstd::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);returnr;
3)std::basic_string<CharT,Traits,Allocator>r=lhs;r.push_back(rhs);returnr;
4)std::basic_string<CharT,Traits,Allocator>r=lhs;r.append(rhs);returnr;
5)std::basic_string<CharT,Traits,Allocator>r=rhs;r.insert(0,lhs);returnr;
6)std::basic_string<CharT,Traits,Allocator>r=rhs;r.insert(r.begin(),lhs);returnr;
7)std::basic_string<CharT,Traits,Allocator>r=rhs;r.insert(0,lhs);returnr;
8)lhs.append(rhs);returnstd::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);returnstd::move(lhs);
11)lhs.push_back(rhs);returnstd::move(lhs);
12)lhs.append(rhs);returnstd::move(lhs);
13,14)rhs.insert(0,lhs);returnstd::move(rhs);
15)rhs.insert(rhs.begin(),lhs);returnstd::move(rhs);
16)rhs.insert(0,lhs);returnstd::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 (
), all rvalue basic_string operands are left in valid but unspecified states.
(since C++11)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 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
is used)(since C++17). Prior to
, the allocator used for the result was determined by historical accident and can vary from overload to overload for no apparent reason. Moreover, for (
), 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:
usingmy_string=std::basic_string<char,std::char_traits<char>,my_allocator<char>>;my_stringcat();constmy_string&dog();my_stringmeow=/* ... */,woof=/* ... */;meow+cat()+/* ... */;// uses select_on_container_copy_construction on meow's allocatorwoof+dog()+/* ... */;// uses allocator of dog()'s return value insteadmeow+woof+meow;// uses select_on_container_copy_construction on meow's allocatormeow+(woof+meow);// uses SOCCC on woof's allocator insteadFor 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 resultmy_string(my_favorite_allocator)+meow+woof+cat()+dog();For better and portable control over allocators, member functions like
,
, and
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 (
), (
), (
), and (
) 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
rules.
macro ValueStdFeature
(C++26)Concatenation of strings and string views, overloads (
), (
), (
), (
)(since C++26)Example
Run this code
#include<iostream>#include<string>#include<string_view>intmain(){std::strings1="Hello";std::strings2="world";constchar*end="!\n";std::cout<<s1+' '+s2+end;std::string_viewwater{" Water"};#if __cpp_lib_string_view >= 202403std::cout<<s1+water+s2<<end;// overload (4), then (1)#elsestd::cout<<s1+std::string(water)+s2<<end;// OK, but less efficient#endif}Output:
Hello world! Hello Waterworld! Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior
C++11 allocator propagation is haphazard and inconsistent made more consistent See also