Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/utility/tuple/operator="

From cppreference.com
< cpp‎ | utility‎ | tuple
(Grammar error.)
m (Synopsis: ~(constexpr since C++20).)
 
(10 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{cpp/utility/tuple/title | operator{{=}}}}
+
{{cpp/utility/tuple/title|operator{{=}}}}
 
{{cpp/utility/tuple/navbar}}
 
{{cpp/utility/tuple/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl rev multi|num=1|since1=c++11|dcl1=
+
{{dcla|num=1|since=c++11|constexpr=c++20|1=
 
tuple& operator=( const tuple& other );
 
tuple& operator=( const tuple& other );
|since2=c++20|dcl2=
 
constexpr tuple& operator=( const tuple& other );
 
 
}}
 
}}
{{dcl rev multi|num=2|since1=c++11|dcl1=
+
{{dcl|num=2|since=c++23|1=
 +
constexpr const tuple& operator=( const tuple& other ) const;
 +
}}
 +
{{dcla|num=3|since=c++11|constexpr=c++20|1=
 
tuple& operator=( tuple&& other ) noexcept(/* see below */);
 
tuple& operator=( tuple&& other ) noexcept(/* see below */);
|since2=c++20|dcl2=
 
constexpr tuple& operator=( tuple&& other ) noexcept(/* see below */);
 
 
}}
 
}}
{{dcl rev multi|num=3|since1=c++11|dcl1=
+
{{dcl|num=4|since=c++23|1=
 +
constexpr const tuple& operator=( tuple&& other ) const;
 +
}}
 +
{{dcla|num=5|since=c++11|constexpr=c++20|1=
 
template< class... UTypes >
 
template< class... UTypes >
 
tuple& operator=( const tuple<UTypes...>& other );
 
tuple& operator=( const tuple<UTypes...>& other );
|since2=c++20|dcl2=
+
}}
 +
{{dcl|num=6|since=c++23|1=
 
template< class... UTypes >
 
template< class... UTypes >
constexpr tuple& operator=( const tuple<UTypes...>& other );
+
constexpr const tuple& operator=( const tuple<UTypes...>& other ) const;
 
}}
 
}}
{{dcl rev multi|num=4|since1=c++11|dcl1=
+
{{dcla|num=7|since=c++11|constexpr=c++20|1=
 
template< class... UTypes >
 
template< class... UTypes >
 
tuple& operator=( tuple<UTypes...>&& other );
 
tuple& operator=( tuple<UTypes...>&& other );
|since2=c++20|dcl2=
+
}}
 +
{{dcl|num=8|since=c++23|1=
 
template< class... UTypes >
 
template< class... UTypes >
constexpr tuple& operator=( tuple<UTypes...>&& other );
+
constexpr const tuple& operator=( tuple<UTypes...>&& other ) const;
 
}}
 
}}
{{dcl rev multi|num=5|since1=c++11|dcl1=
+
{{dcla|num=9|since=c++11|constexpr=c++20|1=
template< class U1, class U2 >
+
template< class E1, class E2 >
tuple& operator=( const std::pair<U1,U2>& p );
+
tuple& operator=( const std::pair<E1, E2>& p );
|since2=c++20|dcl2=
+
template< class U1, class U2 >
+
constexpr tuple& operator=( const std::pair<U1,U2>& p );
+
 
}}
 
}}
{{dcl rev multi|num=6|since1=c++11|dcl1=
+
{{dcl|num=10|since=c++23|1=
template< class U1, class U2 >
+
template< class E1, class E2 >
tuple& operator=( std::pair<U1,U2>&& p );
+
constexpr const tuple& operator=( const std::pair<E1, E2>& p ) const;
|since2=c++20|dcl2=
+
}}
template< class U1, class U2 >
+
{{dcla|num=11|since=c++11|constexpr=c++20|1=
constexpr tuple& operator=( std::pair<U1,U2>&& p );
+
template< class E1, class E2 >
 +
tuple& operator=( std::pair<E1, E2>&& p );
 +
}}
 +
{{dcl|num=12|since=c++23|1=
 +
template< class E1, class E2 >
 +
constexpr const tuple& operator=( std::pair<E1, E2>&& p ) const;
 +
}}
 +
{{dcl|num=13|since=c++23|1=
 +
template< tuple-like UTuple >
 +
constexpr tuple& operator=( UTuple&& u );
 +
}}
 +
{{dcl|num=14|since=c++23|1=
 +
template< tuple-like UTuple >
 +
constexpr const tuple& operator=( UTuple&& u ) const;
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
Replaces the contents of the tuple with the contents of another tuple or a pair.
+
Replaces the contents of the tuple with the contents of another tuple-like object.
 +
 
 +
In the descriptions that follow, let
 +
* {{c|i}} be in the range {{range|​0​|sizeof...(Types)}} in order,
 +
* {{tt|Ti}} be the {{tt|i}}th type in the class template parameter pack {{tt|Types}}, and
 +
* {{tt|Ui}} be the {{tt|i}}th type in a function template parameter pack named {{tt|UTypes}},
 +
where indexing is zero-based.
  
 
@1@ Copy assignment operator. Assigns each element of {{c|other}} to the corresponding element of {{c|*this}}.
 
@1@ Copy assignment operator. Assigns each element of {{c|other}} to the corresponding element of {{c|*this}}.
* This overload is defined as deleted unless {{c|std::is_copy_assignable<T_i>::value}} is {{c|true}} for all {{tt|T_i}} in {{tt|Types}}.
+
@@ This overload is defined as deleted unless {{c|std::is_copy_assignable<Ti>::value}} is {{c|true}} for all {{tt|Ti}}.
 +
 
 +
@2@ Copy assignment operator for const-qualified operand. Assigns each element of {{c|other}} to the corresponding element of {{c|*this}}.
 +
@@ {{cpp/enable if|{{c|std::is_copy_assignable_v<const Ti>}} is {{c|true}} for all {{tt|Ti}}.}}
 
   
 
   
@2@ Move assignment operator. For all {{tt|i}}, assigns {{c|std::forward<Ti>(get<i>(other))}} to {{c|get<i>(*this)}}.
+
@3@ Move assignment operator. For all {{c|i}}, assigns {{c|std::forward<Ti>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.
* {{cpp/enable_if|{{c|std::is_move_assignable<T_i>::value}} is {{c|true}} for all {{tt|T_i}} in {{tt|Types}}}}.
+
@@ {{cpp/enable if|{{c|std::is_move_assignable<Ti>::value}} is {{c|true}} for all {{tt|Ti}}.}}
 +
 +
@4@ Move assignment operator for const-qualified operand. For all {{c|i}}, assigns {{c|std::forward<Ti>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.
 +
@@ {{cpp/enable if|{{c|std::is_assignable_v<const Ti&, Ti>}} is {{c|true}} for all {{tt|Ti}}.}}
 +
 
 +
@5@ For all {{c|i}}, assigns {{c|std::get<i>(other)}} to {{c|std::get<i>(*this)}}.
 +
@@ {{cpp/enable if|{{c|1=sizeof...(Types) == sizeof...(UTypes)}}, and {{c|std::is_assignable<Ti&, const Ui&>::value}} is {{c|true}} for all corresponding pairs of types {{tt|Ti}} and {{tt|Ui}}.}}
 +
 
 +
@6@ For all {{c|i}}, assigns {{c|std::get<i>(other)}} to {{c|std::get<i>(*this)}}.
 +
@@ {{cpp/enable if|{{c|1=sizeof...(Types) == sizeof...(UTypes)}}, and {{c|std::is_assignable_v<const Ti&, const Ui&>}} is {{c|true}} for all corresponding pairs of types {{tt|Ti}} and {{tt|Ui}}.}}
 +
 
 +
@7@ For all {{c|i}}, assigns {{c|std::forward<Ui>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.
 +
@@ {{cpp/enable if|{{c|1=sizeof...(Types) == sizeof...(UTypes)}}, and {{c|std::is_assignable<Ti&, Ui>::value}} is {{c|true}} for all corresponding pairs of types {{tt|Ti}}and {{tt|Ui}}.}}
 +
 
 +
@8@ For all {{c|i}}, assigns {{c|std::forward<Ui>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.
 +
@@ {{cpp/enable if|{{c|1=sizeof...(Types) == sizeof...(UTypes)}}, and {{c|std::is_assignable_v<const Ti&, Ui>}} is {{c|true}} for all corresponding pairs of types {{tt|Ti}} and {{tt|Ui}}.}}
 +
 
 +
@9@ Assigns {{c|p.first}} to the first element of {{c|*this}} and {{c|p.second}} to the second element of {{c|*this}}.
 +
@@ {{cpp/enable if|
 +
* {{c|1=sizeof...(Types) == 2}},
 +
* {{c|std::is_assignable<T0&, const E1&>::value}} is {{c|true}}, and
 +
* {{c|std::is_assignable<T1&, const E2&>::value}} is {{c|true}}.}}
 +
 
 +
@10@ Assigns {{c|p.first}} to the first element and {{c|p.second}} to the second element.
 +
@@ {{cpp/enable if|
 +
* {{c|1=sizeof...(Types) == 2}},
 +
* {{c|std::is_assignable_v<const T0&, const E1&>}} is {{c|true}}, and
 +
* {{c|std::is_assignable_v<const T1&, const E2&>}} is {{c|true}}.}}
  
@3@ For all {{tt|i}}, assigns {{c|std::get<i>(other)}} to {{c|std::get<i>(*this)}}.
+
@11@ Assigns {{c|std::forward<E1>(p.first)}} to the first element of {{c|*this}} and {{c|std::forward<E2>(p.second)}} to the second element of {{c|*this}}.
* {{cpp/enable_if|{{c|1=sizeof...(UTypes) == sizeof...(Types)}} and {{c|std::is_assignable<T_i&, const U_i&>::value}} is {{c|true}} for all corresponding pairs of types {{tt|T_i}} in {{tt|Types}} and {{tt|U_i}} in {{tt|UTypes}}}}.
+
@@ {{cpp/enable if|
 +
* {{c|1=sizeof...(Types) == 2}},
 +
* {{c|std::is_assignable_v<T0&, E1>}} is {{c|true}}, and
 +
* {{c|std::is_assignable_v<T1&, E2>}} is {{c|true}}.}}
  
@4@ For all {{tt|i}}, assigns {{c|std::forward<Ui>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.
+
@12@ Assigns {{c|std::forward<E1>(p.first)}} to the first element and {{c|std::forward<E2>(p.second)}} to the second element.
* {{cpp/enable_if|{{c|1=sizeof...(UTypes) == sizeof...(Types)}} and {{c|std::is_assignable<T_i&, U_i>::value}} is {{c|true}} for all corresponding pairs of types {{tt|T_i}} in {{tt|Types}} and {{tt|U_i}} in {{tt|UTypes}}}}.
+
@@ {{cpp/enable if|
 +
* {{c|1=sizeof...(Types) == 2}},
 +
* {{c|std::is_assignable_v<const T0&, E1>}} is {{c|true}}, and
 +
* {{c|std::is_assignable_v<const T1&, E2>}} is {{c|true}}.}}
  
@5@ Assigns {{c|p.first}} to the first element of {{c|*this}} and {{c|p.second}} to the second element of {{c|*this}}.
+
@13@ For all {{c|i}}, assigns {{c|std::get<i>(std::forward<UTuple>(u))}} to {{c|std::get<i>(*this)}}.
* {{cpp/enable_if|{{c|1=sizeof...(Types) == 2}}, {{c|std::is_assignable<T_0&, const U1&>::value}} and {{c|std::is_assignable<T_1&, const U2&>::value}} are both {{c|true}}, where {{tt|T_0}} and {{tt|T_1}} are the two types constituting {{tt|Types}}}}.
+
@@ {{cpp/enable if|
 +
* {{c|std::same_as<std::remove_cvref_t<UTuple>, std::tuple>}} is {{c|false}},
 +
* {{c/core|std::remove_cvref_t<UTuple>}} is not a specialization of {{lc|std::ranges::subrange}},
 +
* {{c|sizeof...(Types)}} equals {{c|std::tuple_size_v<std::remove_cvref_t<UTuple>>}}, and
 +
* {{c|std::is_assignable_v<Ti&, decltype(std::get<i>(std::forward<UTuple>(u)))>}} is {{c|true}} for all {{c|i}}.}}
  
@6@ Assigns {{c|std::forward<U1>(p.first)}} to the first element of {{c|*this}} and {{c|std::forward<U2>(p.second)}} to the second element of {{c|*this}}.
+
@14@ For all {{c|i}}, assigns {{c|std::get<i>(std::forward<UTuple>(u))}} to {{c|std::get<i>(*this)}}.
* {{cpp/enable_if|{{c|std::is_assignable<T_0&, U1>::value}} and {{c|std::is_assignable<T_1&, U2>::value}} are both {{c|true}}, where {{tt|T_0}} and {{tt|T_1}} are the two types constituting {{tt|Types}}}}.
+
@@ {{cpp/enable if|
 +
* {{c|std::same_as<std::remove_cvref_t<UTuple>, std::tuple>}} is {{c|false}},
 +
* {{c/core|std::remove_cvref_t<UTuple>}} is not a specialization of {{lc|std::ranges::subrange}},
 +
* {{c|sizeof...(Types)}} equals {{c|std::tuple_size_v<std::remove_cvref_t<UTuple>>}}, and
 +
* {{c|std::is_assignable_v<const Ti&, decltype(std::get<i>(std::forward<UTuple>(u)))>}} is {{c|true}} for all {{c|i}}.}}
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | other | tuple to replace the contents of this tuple }}
+
{{par|other|tuple to replace the contents of this tuple}}
{{par | p | pair to replace the contents of this 2-tuple }}
+
{{par|p|pair to replace the contents of this 2-tuple}}
 +
{{par|u|{{rlpi|tuple-like}} object to replace the contents of this tuple}}
 
{{par end}}  
 
{{par end}}  
  
Line 72: Line 137:
  
 
===Exceptions===
 
===Exceptions===
@1@ {{cpp/impldef exception item}}
+
@1,2@ {{cpp/impldef exception item|if=the assignment of one of the types in {{tt|Types}} throws an exception}}
  
@2@ {{noexcept|
+
@3@ {{noexcept|
 
     std::is_nothrow_move_assignable<T0>::value &&
 
     std::is_nothrow_move_assignable<T0>::value &&
 
     std::is_nothrow_move_assignable<T1>::value &&
 
     std::is_nothrow_move_assignable<T1>::value &&
Line 81: Line 146:
 
}}
 
}}
  
@3-6@ {{cpp/impldef exception item}}
+
@4-14@ {{cpp/impldef exception item|if=the assignment of one of the types in {{tt|Types}} throws an exception}}
  
 
===Example===
 
===Example===
 
{{example
 
{{example
| code=
+
|code=
 
#include <iostream>
 
#include <iostream>
 
#include <string>
 
#include <string>
 +
#include <string_view>
 
#include <tuple>
 
#include <tuple>
 
#include <utility>
 
#include <utility>
 
#include <vector>
 
#include <vector>
  
// helper function to print std::vector
+
// helper function to print std::vector<int>
template<class Os, class T> Os& operator<< (Os& os, std::vector<T> const& v) {
+
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
     os << "{";
+
{
 +
     os << '{';
 
     for (std::size_t t = 0; t != v.size(); ++t)
 
     for (std::size_t t = 0; t != v.size(); ++t)
         os << v[t] << (t+1 < v.size() ? ",":"");
+
         os << v[t] << (t + 1 < v.size() ? ", " : "");
     return os << "}";
+
     return os << '}';
 
}
 
}
  
 
// helpers to print a tuple of any size
 
// helpers to print a tuple of any size
template<class Os, class Tuple, std::size_t N>
+
template<class... Args>
struct TuplePrinter {
+
void print_tuple(std::string_view name, const std::tuple<Args...>& t)
    static void print(Os& os, const Tuple& t) {
+
{
        TuplePrinter<Os, Tuple, N-1>::print(os, t);
+
     std::cout << name << " = {";
        os << ", " << std::get<N-1>(t);
+
     std::apply([&](auto&& arg, auto&&... args)
     }
+
    {
};
+
         std::cout << arg;
 
+
        ((std::cout << ", " << args), ...);
template<class Os, class Tuple>
+
    }, t);
struct TuplePrinter<Os, Tuple, 1>{
+
     std::cout << '}';
     static void print(Os& os, const Tuple& t) {
+
         os << std::get<0>(t);
+
    }
+
};
+
 
+
template<class Os, class... Args>
+
Os& operator<< (Os& os, const std::tuple<Args...>& t) {
+
    os << "{ ";
+
    TuplePrinter<Os, decltype(t), sizeof...(Args)>::print(os, t);
+
     return os << " }";
+
 
}
 
}
  
struct line{ int len{60}; };
+
template<class Tuple1, class Tuple2>
template<class Os> Os& operator<< (Os& os, line l) {
+
void print_tuples(std::string_view name1, const Tuple1& t1,
     while (l.len-- > 0) std::cout << "";
+
                  std::string_view name2, const Tuple2& t2)
     return os << '\n';
+
{
 +
     print_tuple(name1, t1);
 +
    std::cout << ", ";
 +
     print_tuple(name2, std::tuple(t2));
 +
    std::cout << "\n\n";
 
}
 
}
  
int main() {
+
int main()
 +
{
 +
    // Tuple to tuple examples //
 
     std::tuple<int, std::string, std::vector<int>>
 
     std::tuple<int, std::string, std::vector<int>>
         t1{1, "alpha", {1, 2, 3} }, t2{2, "beta", {4, 5} };
+
         t1{1, "alpha", {1, 2, 3}<!---->},
     std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
+
        t2{2, "beta", {4, 5}<!---->};
     t1 = t2; // (1) operator=( const tuple& other );
+
     print_tuples("1) t1", t1, "t2", t2);
     std::cout << "t1 = t2;\n" "t1 = " << t1 << ", t2 = " << t2 << '\n' << line{};
+
   
 +
    // Normal copy assignment
 +
    // operator=( const tuple& other );
 +
    t1 = t2;
 +
    print_tuples("2) t1 = t2;\n   t1", t1, "t2", t2);
 +
   
 +
    // Normal move assignment
 +
    // operator=( tuple&& other );
 +
     t1 = std::move(t2);
 +
    print_tuples("3) t1 = std::move(t2);\n  t1", t1, "t2", t2);
 +
   
 +
    // Converting copy assignment
 +
    // operator=( const tuple<UTypes...>& other );
 +
     std::tuple<short, const char*, std::vector<int>> t3{3, "gamma", {6, 7, 8}<!---->};
 +
    t1 = t3;
 +
    print_tuples("4) t1 = t3;\n   t1", t1, "t3", t3);
 +
   
 +
    // Converting move assignment
 +
    // operator=( tuple<UTypes...>&& other );
 +
    t1 = std::move(t3);
 +
    print_tuples("5) t1 = std::move(t3);\n  t1", t1, "t3", t3);
 +
   
 +
    // Pair to tuple examples //
 +
    std::tuple<std::string, std::vector<int>> t4{"delta", {10, 11, 12}<!---->};
 +
    std::pair<const char*, std::vector<int>> p1{"epsilon", {14, 15, 16}<!---->};
 +
    print_tuples("6) t4", t4, "p1", p1);
 +
   
 +
    // Converting copy assignment from std::pair
 +
    // operator=( const std::pair<U1, U2>& p );
 +
    t4 = p1;
 +
    print_tuples("7) t4 = p1;\n   t4", t4, "p1", p1);
 +
   
 +
    // Converting move assignment from std::pair
 +
    // operator=( std::pair<U1, U2>&& p );
 +
    t4 = std::move(p1);
 +
    print_tuples("8) t4 = std::move(p1);\n  t4", t4, "p1", p1);
 +
}
 +
|p=true
 +
|output=
 +
1) t1 = {1, alpha, {1, 2, 3}<!---->}, t2 = {2, beta, {4, 5}<!---->}
  
    t1 = std::move(t2); // (2) operator=( tuple&& other );
+
2) t1 = t2;
    std::cout << "t1 = std::move(t2);\n" "t1 = " << t1 << ", t2 = " << t2 << '\n' << line{};
+
  t1 = {2, beta, {4, 5}<!---->}, t2 = {2, beta, {4, 5}<!---->}
  
    std::tuple<short, const char*, std::vector<int>> t3{3, "gamma", {6,7,8} };
+
3) t1 = std::move(t2);
    t1 = t3; // (3) operator=( const tuple<UTypes...>& other );
+
  t1 = {2, beta, {4, 5}<!---->}, t2 = {2, , {}<!---->}
    std::cout << "t1 = t3; \n" "t1 = " << t1 << ", t3 = " << t3 << '\n' << line{};
+
  
    t1 = std::move(t3); // (4) operator=( tuple<UTypes...>&& other );
+
4) t1 = t3;
    std::cout << "t1 = std::move(t3);\n" "t1 = " << t1 << ", t3 = " << t3 << '\n' << line{};
+
  t1 = {3, gamma, {6, 7, 8}<!---->}, t3 = {3, gamma, {6, 7, 8}<!---->}
  
    std::tuple<std::string, std::vector<int>> t4{"delta", {10,11,12} };
+
5) t1 = std::move(t3);
    std::pair<const char*, std::vector<int>> p1{"epsilon", {14,15,16} };
+
  t1 = {3, gamma, {6, 7, 8}<!---->}, t3 = {3, gamma, {}<!---->}
    std::cout << "t4 = " << t4 << ", "
+
              << "p1 = { " << p1.first << ", " << p1.second << " };\n";
+
    t4 = p1; // (5) operator=( const std::pair<U1,U2>& p );
+
    std::cout << "t4 = p1;\n" "t4 = " << t4
+
              << ", p1 = { " << p1.first << ", " << p1.second << " };\n" << line{};
+
  
    t4 = std::move(p1); // (6) operator=( std::pair<U1,U2>&& p );
+
6) t4 = {delta, {10, 11, 12}<!---->}, p1 = {epsilon, {14, 15, 16}<!---->}
    std::cout << "t4 = std::move(p1);\n" "t4 = " << t4
+
 
              << ", p1 = { " << p1.first << ", " << p1.second << " };\n";
+
7) t4 = p1;
}
+
  t4 = {epsilon, {14, 15, 16}<!---->}, p1 = {epsilon, {14, 15, 16}<!---->}
| output=
+
 
t1 = { 1, alpha, {1,2,3} }, t2 = { 2, beta, {4,5} }
+
8) t4 = std::move(p1);
t1 = t2;
+
  t4 = {epsilon, {14, 15, 16}<!---->}, p1 = {epsilon, {}<!---->}
t1 = { 2, beta, {4,5} }, t2 = { 2, beta, {4,5} }
+
────────────────────────────────────────────────────────────
+
t1 = std::move(t2);
+
t1 = { 2, beta, {4,5} }, t2 = { 2, , {} }
+
────────────────────────────────────────────────────────────
+
t1 = t3;
+
t1 = { 3, gamma, {6,7,8} }, t3 = { 3, gamma, {6,7,8} }
+
────────────────────────────────────────────────────────────
+
t1 = std::move(t3);
+
t1 = { 3, gamma, {6,7,8} }, t3 = { 3, gamma, {} }
+
────────────────────────────────────────────────────────────
+
t4 = { delta, {10,11,12} }, p1 = { epsilon, {14,15,16} };
+
t4 = p1;
+
t4 = { epsilon, {14,15,16} }, p1 = { epsilon, {14,15,16} };
+
────────────────────────────────────────────────────────────
+
t4 = std::move(p1);
+
t4 = { epsilon, {14,15,16} }, p1 = { epsilon, {} };
+
 
}}
 
}}
  
 
===Defect reports===
 
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=lwg|dr=2729|std=C++11|before={{tt|1=tuple::operator=}} was unconstrained and might<br>result in unnecessary undefined behavior|after=constrained}}
+
{{dr list item|wg=lwg|dr=2729|std=C++11|before={{c/core|1=operator=}} was unconstrained and might<br>result in unnecessary undefined behavior|after=constrained}}
 
{{dr list end}}
 
{{dr list end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
 +
{{dsc inc|cpp/utility/tuple/dsc constructor}}
 +
{{dsc inc|cpp/utility/pair/dsc operator{{=}}}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 19:23, 13 May 2024

 
 
Utilities library
General utilities
Relational operators (deprecated in C++20)
 
 
tuple& operator=( const tuple& other );
(1) (since C++11)
(constexpr since C++20)
constexpr const tuple& operator=( const tuple& other ) const;
(2) (since C++23)
tuple& operator=( tuple&& other ) noexcept(/* see below */);
(3) (since C++11)
(constexpr since C++20)
constexpr const tuple& operator=( tuple&& other ) const;
(4) (since C++23)
template< class... UTypes >
tuple& operator=( const tuple<UTypes...>& other );
(5) (since C++11)
(constexpr since C++20)
template< class... UTypes >
constexpr const tuple& operator=( const tuple<UTypes...>& other ) const;
(6) (since C++23)
template< class... UTypes >
tuple& operator=( tuple<UTypes...>&& other );
(7) (since C++11)
(constexpr since C++20)
template< class... UTypes >
constexpr const tuple& operator=( tuple<UTypes...>&& other ) const;
(8) (since C++23)
template< class E1, class E2 >
tuple& operator=( const std::pair<E1, E2>& p );
(9) (since C++11)
(constexpr since C++20)
template< class E1, class E2 >
constexpr const tuple& operator=( const std::pair<E1, E2>& p ) const;
(10) (since C++23)
template< class E1, class E2 >
tuple& operator=( std::pair<E1, E2>&& p );
(11) (since C++11)
(constexpr since C++20)
template< class E1, class E2 >
constexpr const tuple& operator=( std::pair<E1, E2>&& p ) const;
(12) (since C++23)
template< tuple-like UTuple >
constexpr tuple& operator=( UTuple&& u );
(13) (since C++23)
template< tuple-like UTuple >
constexpr const tuple& operator=( UTuple&& u ) const;
(14) (since C++23)

Replaces the contents of the tuple with the contents of another tuple-like object.

In the descriptions that follow, let

  • i be in the range [0sizeof...(Types)) in order,
  • Ti be the ith type in the class template parameter pack Types, and
  • Ui be the ith type in a function template parameter pack named UTypes,

where indexing is zero-based.

1) Copy assignment operator. Assigns each element of other to the corresponding element of *this.
This overload is defined as deleted unless std::is_copy_assignable<Ti>::value is true for all Ti.
2) Copy assignment operator for const-qualified operand. Assigns each element of other to the corresponding element of *this.
This overload participates in overload resolution only if std::is_copy_assignable_v<const Ti> is true for all Ti.
3) Move assignment operator. For all i, assigns std::forward<Ti>(std::get<i>(other)) to std::get<i>(*this).
This overload participates in overload resolution only if std::is_move_assignable<Ti>::value is true for all Ti.
4) Move assignment operator for const-qualified operand. For all i, assigns std::forward<Ti>(std::get<i>(other)) to std::get<i>(*this).
This overload participates in overload resolution only if std::is_assignable_v<const Ti&, Ti> is true for all Ti.
5) For all i, assigns std::get<i>(other) to std::get<i>(*this).
This overload participates in overload resolution only if sizeof...(Types) == sizeof...(UTypes), and std::is_assignable<Ti&, const Ui&>::value is true for all corresponding pairs of types Ti and Ui.
6) For all i, assigns std::get<i>(other) to std::get<i>(*this).
This overload participates in overload resolution only if sizeof...(Types) == sizeof...(UTypes), and std::is_assignable_v<const Ti&, const Ui&> is true for all corresponding pairs of types Ti and Ui.
7) For all i, assigns std::forward<Ui>(std::get<i>(other)) to std::get<i>(*this).
This overload participates in overload resolution only if sizeof...(Types) == sizeof...(UTypes), and std::is_assignable<Ti&, Ui>::value is true for all corresponding pairs of types Tiand Ui.
8) For all i, assigns std::forward<Ui>(std::get<i>(other)) to std::get<i>(*this).
This overload participates in overload resolution only if sizeof...(Types) == sizeof...(UTypes), and std::is_assignable_v<const Ti&, Ui> is true for all corresponding pairs of types Ti and Ui.
9) Assigns p.first to the first element of *this and p.second to the second element of *this.
This overload participates in overload resolution only if
10) Assigns p.first to the first element and p.second to the second element.
This overload participates in overload resolution only if
11) Assigns std::forward<E1>(p.first) to the first element of *this and std::forward<E2>(p.second) to the second element of *this.
This overload participates in overload resolution only if
12) Assigns std::forward<E1>(p.first) to the first element and std::forward<E2>(p.second) to the second element.
This overload participates in overload resolution only if
13) For all i, assigns std::get<i>(std::forward<UTuple>(u)) to std::get<i>(*this).
This overload participates in overload resolution only if
14) For all i, assigns std::get<i>(std::forward<UTuple>(u)) to std::get<i>(*this).
This overload participates in overload resolution only if

Contents

[edit] Parameters

other - tuple to replace the contents of this tuple
p - pair to replace the contents of this 2-tuple
u - tuple-like object to replace the contents of this tuple

[edit] Return value

*this

[edit] Exceptions

1,2) May throw implementation-defined exceptionsif the assignment of one of the types in Types throws an exception.
3)
noexcept specification:  
noexcept(

    std::is_nothrow_move_assignable<T0>::value &&
    std::is_nothrow_move_assignable<T1>::value &&
    std::is_nothrow_move_assignable<T2>::value &&
    ...

)
4-14) May throw implementation-defined exceptionsif the assignment of one of the types in Types throws an exception.

[edit] Example

#include <iostream>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
 
// helper function to print std::vector<int>
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
    os << '{';
    for (std::size_t t = 0; t != v.size(); ++t)
        os << v[t] << (t + 1 < v.size() ? ", " : "");
    return os << '}';
}
 
// helpers to print a tuple of any size
template<class... Args>
void print_tuple(std::string_view name, const std::tuple<Args...>& t)
{
    std::cout << name << " = {";
    std::apply([&](auto&& arg, auto&&... args)
    {
        std::cout << arg;
        ((std::cout << ", " << args), ...);
    }, t);
    std::cout << '}';
}
 
template<class Tuple1, class Tuple2>
void print_tuples(std::string_view name1, const Tuple1& t1,
                  std::string_view name2, const Tuple2& t2)
{
    print_tuple(name1, t1);
    std::cout << ", ";
    print_tuple(name2, std::tuple(t2));
    std::cout << "\n\n";
}
 
int main()
{
    // Tuple to tuple examples //
    std::tuple<int, std::string, std::vector<int>>
        t1{1, "alpha", {1, 2, 3}},
        t2{2, "beta", {4, 5}};
    print_tuples("1) t1", t1, "t2", t2);
 
    // Normal copy assignment
    // operator=( const tuple& other );
    t1 = t2;
    print_tuples("2) t1 = t2;\n   t1", t1, "t2", t2);
 
    // Normal move assignment
    // operator=( tuple&& other );
    t1 = std::move(t2);
    print_tuples("3) t1 = std::move(t2);\n   t1", t1, "t2", t2);
 
    // Converting copy assignment
    // operator=( const tuple<UTypes...>& other );
    std::tuple<short, const char*, std::vector<int>> t3{3, "gamma", {6, 7, 8}};
    t1 = t3;
    print_tuples("4) t1 = t3;\n   t1", t1, "t3", t3);
 
    // Converting move assignment
    // operator=( tuple<UTypes...>&& other );
    t1 = std::move(t3);
    print_tuples("5) t1 = std::move(t3);\n   t1", t1, "t3", t3);
 
    // Pair to tuple examples //
    std::tuple<std::string, std::vector<int>> t4{"delta", {10, 11, 12}};
    std::pair<const char*, std::vector<int>> p1{"epsilon", {14, 15, 16}};
    print_tuples("6) t4", t4, "p1", p1);
 
    // Converting copy assignment from std::pair
    // operator=( const std::pair<U1, U2>& p );
    t4 = p1;
    print_tuples("7) t4 = p1;\n   t4", t4, "p1", p1);
 
    // Converting move assignment from std::pair
    // operator=( std::pair<U1, U2>&& p );
    t4 = std::move(p1);
    print_tuples("8) t4 = std::move(p1);\n   t4", t4, "p1", p1);
}

Possible output:

1) t1 = {1, alpha, {1, 2, 3}}, t2 = {2, beta, {4, 5}}
 
2) t1 = t2;
   t1 = {2, beta, {4, 5}}, t2 = {2, beta, {4, 5}}
 
3) t1 = std::move(t2);
   t1 = {2, beta, {4, 5}}, t2 = {2, , {}}
 
4) t1 = t3;
   t1 = {3, gamma, {6, 7, 8}}, t3 = {3, gamma, {6, 7, 8}}
 
5) t1 = std::move(t3);
   t1 = {3, gamma, {6, 7, 8}}, t3 = {3, gamma, {}}
 
6) t4 = {delta, {10, 11, 12}}, p1 = {epsilon, {14, 15, 16}}
 
7) t4 = p1;
   t4 = {epsilon, {14, 15, 16}}, p1 = {epsilon, {14, 15, 16}}
 
8) t4 = std::move(p1);
   t4 = {epsilon, {14, 15, 16}}, p1 = {epsilon, {}}

[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
LWG 2729 C++11 operator= was unconstrained and might
result in unnecessary undefined behavior
constrained

[edit] See also

constructs a new tuple
(public member function) [edit]
assigns the contents
(public member function of std::pair<T1,T2>) [edit]