Namespaces
Variants
Views
Actions

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

From cppreference.com
< cpp‎ | utility‎ | tuple
(Exceptions: How is #6 noexcept?)
m (Synopsis: ~(constexpr since C++20).)
 
(20 intermediate revisions by 8 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 | num=1 | since=c++11 | 1=
+
{{dcla|num=1|since=c++11|constexpr=c++20|1=
 
tuple& operator=( const tuple& other );
 
tuple& operator=( const tuple& other );
 
}}
 
}}
{{dcl | num=2 | since=c++11 | 1=
+
{{dcl|num=2|since=c++23|1=
tuple& operator=( tuple&& other );
+
constexpr const tuple& operator=( const tuple& other ) const;
 
}}
 
}}
{{dcl | num=3 | since=c++11 | 1=
+
{{dcla|num=3|since=c++11|constexpr=c++20|1=
 +
tuple& operator=( tuple&& other ) noexcept(/* see below */);
 +
}}
 +
{{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 );
 
}}
 
}}
{{dcl | num=4 | since=c++11 | 1=
+
{{dcl|num=6|since=c++23|1=
 +
template< class... UTypes >
 +
constexpr const tuple& operator=( const tuple<UTypes...>& other ) const;
 +
}}
 +
{{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 );
 
}}
 
}}
{{dcl | num=5 | since=c++11 | 1=
+
{{dcl|num=8|since=c++23|1=
template< class U1, class U2 >
+
template< class... UTypes >
tuple& operator=( const pair<U1,U2>& p );
+
constexpr const tuple& operator=( tuple<UTypes...>&& other ) const;
 +
}}
 +
{{dcla|num=9|since=c++11|constexpr=c++20|1=
 +
template< class E1, class E2 >
 +
tuple& operator=( const std::pair<E1, E2>& p );
 +
}}
 +
{{dcl|num=10|since=c++23|1=
 +
template< class E1, class E2 >
 +
constexpr const tuple& operator=( const std::pair<E1, E2>& p ) const;
 +
}}
 +
{{dcla|num=11|since=c++11|constexpr=c++20|1=
 +
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=6 | since=c++11 | 1=
+
{{dcl|num=14|since=c++23|1=
template< class U1, class U2 >
+
template< tuple-like UTuple >
tuple& operator=( pair<U1,U2>&& p );
+
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.
  
1) Copy assignment operator. Replaces each element with a copy of the corresponding element of {{tt|other}}.
+
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}}.
 +
@@ 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}}.}}
 +
 +
@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<Ti>::value}} is {{c|true}} for all {{tt|Ti}}.}}
 
   
 
   
2) Move assignment operator. Replaces each element with the corresponding element of {{tt|other}} using move semantics.  
+
@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}}.}}
  
3) For all {{tt|i}}, assigns {{c|std::get<i>(other)}} to {{c|std::get<i>(*this)}}.
+
@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}}.}}
  
4) For all {{tt|i}}, assigns {{c|std::forward<Ui>(std::get<i>(other))}} to {{c|std::get<i>(*this)}}.  
+
@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}}.}}
  
5) Assigns {{c|p.first}} to the first element of {{c|*this}} and {{c|p.second}} to the second element of {{c|*this}}.
+
@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}}.}}
  
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}}.
+
@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}}.}}
 +
 
 +
@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...(Types) == 2}},
 +
* {{c|std::is_assignable_v<T0&, E1>}} is {{c|true}}, and
 +
* {{c|std::is_assignable_v<T1&, E2>}} is {{c|true}}.}}
 +
 
 +
@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...(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}}.}}
 +
 
 +
@13@ For all {{c|i}}, assigns {{c|std::get<i>(std::forward<UTuple>(u))}} to {{c|std::get<i>(*this)}}.
 +
@@ {{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}}.}}
 +
 
 +
@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::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 50: Line 137:
  
 
===Exceptions===
 
===Exceptions===
1) (none)
+
@1,2@ {{cpp/impldef exception item|if=the assignment of one of the types in {{tt|Types}} throws an exception}}
  
2) {{noexcept|
+
@3@ {{noexcept|
     is_nothrow_move_assignable<T0>::value &&
+
     std::is_nothrow_move_assignable<T0>::value &&
     is_nothrow_move_assignable<T1>::value &&
+
     std::is_nothrow_move_assignable<T1>::value &&
     is_nothrow_move_assignable<T2>::value &&
+
     std::is_nothrow_move_assignable<T2>::value &&
 
     ...
 
     ...
 
}}
 
}}
  
3-6) (none)
+
@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=
| output=
+
#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);
 +
}
 +
|p=true
 +
|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, {}<!---->}
 
}}
 
}}
  
===See also===
+
===Defect reports===
 +
{{dr list begin}}
 +
{{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}}
  
 +
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
 +
{{dsc inc|cpp/utility/tuple/dsc constructor}}
 +
{{dsc inc|cpp/utility/pair/dsc operator{{=}}}}
 
{{dsc end}}
 
{{dsc end}}
  
[[de:cpp/utility/tuple/operator=]]
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
[[es:cpp/utility/tuple/operator=]]
+
[[fr:cpp/utility/tuple/operator=]]
+
[[it:cpp/utility/tuple/operator=]]
+
[[ja:cpp/utility/tuple/operator=]]
+
[[pt:cpp/utility/tuple/operator=]]
+
[[ru:cpp/utility/tuple/operator=]]
+
[[zh:cpp/utility/tuple/operator=]]
+

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]