std::tuple::tuple(3)
π NAME π
std::tuple::tuple β bestie, it's the constructor of std::tuple, and it's lowkey the whole personality of the C++ Standard Library π
(this page comes from the C++ Standard Library section, section 3, and it's giving "i contain multitudes" energy)
β¨ SYNOPSIS β¨
Defined in header <tuple> π
(1) constexpr tuple();
(since C++11) Β· (conditionally explicit)
(2) tuple( const Types&... args );
(constexpr since C++14) Β· (conditionally explicit)
(3) template< class... UTypes >
tuple( UTypes&&... args );
(since C++11) Β· (constexpr since C++14) Β· (conditionally explicit)
(4) template< class... UTypes >
constexpr tuple( tuple<UTypes...>& other );
(since C++23) Β· (conditionally explicit)
(5) template< class... UTypes >
tuple( const tuple<UTypes...>& other );
(since C++11) Β· (constexpr since C++14) Β· (conditionally explicit)
(6) template< class... UTypes >
tuple( tuple<UTypes...>&& other );
(since C++11) Β· (constexpr since C++14) Β· (conditionally explicit)
(7) template< class... UTypes >
constexpr tuple( const tuple<UTypes...>&& other );
(since C++23) Β· (conditionally explicit)
(8) template< class U1, class U2 >
constexpr tuple( std::pair<U1, U2>& p );
(since C++23) Β· (conditionally explicit)
(9) template< class U1, class U2 >
tuple( const std::pair<U1, U2>& p );
(since C++11) Β· (constexpr since C++14) Β· (conditionally explicit)
(10) template< class U1, class U2 >
tuple( std::pair<U1, U2>&& p );
(since C++11) Β· (constexpr since C++14) Β· (conditionally explicit)
(11) template< class U1, class U2 >
constexpr tuple( const std::pair<U1, U2>&& p );
(since C++23) Β· (conditionally explicit)
(12) template< tuple-like UTuple >
constexpr tuple( UTuple&& u );
(since C++23) Β· (conditionally explicit)
(13) tuple( const tuple& other ) = default;
(since C++11)
(14) tuple( tuple&& other ) = default;
(since C++11)
πΈ Allocator-extended constructors πΈ
(yes there are so many of them, and yes they all have an allocator moment)
(15) template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(16) template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
const Types&... args );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(17) template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
UTypes&&... args );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(18) template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
tuple<UTypes...>& other );
(since C++23) Β· (conditionally explicit)
(19) template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
const tuple<UTypes...>& other );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(20) template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
tuple<UTypes...>&& other );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(21) template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
const tuple<UTypes...>&& other );
(since C++23) Β· (conditionally explicit)
(22) template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
std::pair<U1, U2>& p );
(since C++23) Β· (conditionally explicit)
(23) template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
const std::pair<U1, U2>& p );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(24) template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
std::pair<U1, U2>&& p );
(since C++11) Β· (constexpr since C++20) Β· (conditionally explicit)
(25) template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
const std::pair<U1, U2>&& p );
(since C++23) Β· (conditionally explicit)
(26) template< class Alloc, tuple-like UTuple >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
UTuple&& u );
(since C++23) Β· (conditionally explicit)
(27) template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
const tuple& other );
(since C++11) Β· (constexpr since C++20)
(28) template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
tuple&& other );
(since C++11) Β· (constexpr since C++20)
π DESCRIPTION π
Constructs a new tuple. That's it, that's the vibe β¨ (okay no, there's so much more, buckle up bestie).
In the descriptions that follow, let
ibe in the range[0, sizeof...(Types))in order,Tibe theith type inTypes, andUibe theith type in a template parameter pack namedUTypes,
where indexing is zero-based. (zero-based, always, no cap) π«Ά
- Default constructor. Value-initializes all elements, if any. The default constructor is trivial if
sizeof...(Types) == 0.- This overload participates in overload resolution only if
std::is_default_constructible<Ti>::valueis true for alli. - The constructor is explicit if and only if
Tiis not copy-list-initializable from{}for at least onei.
- This overload participates in overload resolution only if
- Direct constructor. Initializes each element of the tuple with the corresponding parameter.
- This overload participates in overload resolution only if
sizeof...(Types) >= 1andstd::is_copy_constructible<Ti>::valueis true for alli. - This constructor is explicit if and only if
std::is_convertible<const Ti&, Ti>::valueis false for at least onei.
- This overload participates in overload resolution only if
- Converting constructor. Initializes each element of the tuple with the corresponding value in
std::forward<UTypes>(args).- This overload participates in overload resolution only if
sizeof...(Types) == sizeof...(UTypes),sizeof...(Types) >= 1,std::is_constructible<Ti, Ui>::valueis true for alli, and- let
Dbestd::decay<U0>::type(until C++20)std::remove_cvref_t<U0>(since C++20),- if
sizeof...(Types) == 1, thenDis notstd::tuple, otherwise, - if
sizeof...(Types) == 2orsizeof...(Types) == 3, then eitherDis notstd::allocator_arg_t, orT0isstd::allocator_arg_t.
- if
- The constructor is explicit if and only if
std::is_convertible<Ui, Ti>::valueis false for at least onei. - This constructor is defined as deleted if the initialization of any element that is a reference would bind it to a temporary object. (since C++23) (!! dangling reference behavior, we do NOT stan, it's literally deleted for a reason bestie)
- This overload participates in overload resolution only if
- 4-7) Converting constructor. Initializes each element of the tuple with the corresponding element of
other.
Formally, let FWD(other) be std::forward<decltype(other)>(other), for all i, initializes ith element of the tuple with std::get<i>(FWD(other)).
- This overload participates in overload resolution only if
sizeof...(Types) == sizeof...(UTypes),std::is_constructible_v<Ti, decltype(std::get<i>(FWD(other)))>is true for alli, and- either
sizeof...(Types)is not1, or- (when
Types...expands toTandUTypes...expands toU)std::is_convertible_v<decltype(other), T>,std::is_constructible_v<T, decltype(other)>, andstd::is_same_v<T, U>are all false.
- These constructors are explicit if and only if
std::is_convertible_v<decltype(std::get<i>(FWD(other))), Ti>is false for at least onei. - These constructors are defined as deleted if the initialization of any element that is a reference would bind it to a temporary object. (since C++23) π
- 8-11) Pair constructor. Constructs a 2-element tuple with each element constructed from the corresponding element of
p.
Formally, let FWD(p) be std::forward<decltype(p)>(p), initializes the first element with std::get<0>(FWD(p)) and the second element with std::get<1>(FWD(p)). π
- this overload only shows up in overload resolution if all of these are true:
sizeof...(Types) == 2,std::is_constructible_v<T0, decltype(std::get<0>(FWD(p)))>is true, andstd::is_constructible_v<T1, decltype(std::get<1>(FWD(p)))>is true.
- it's
explicitif and only ifstd::is_convertible_v<decltype(std::get<0>(FWD(p))), T0>orstd::is_convertible_v<decltype(std::get<1>(FWD(p))), T1>isfalse. - these constructors are defined as deleted if initializing any element that's a reference would bind it to a temporary object (since C++23).
12) the tuple-like constructor β¨ it builds a tuple where each element comes from the matching element of u.
Formally, for every i, it initializes the ith element of the tuple with std::get<i>(std::forward<UTuple>(u)).
- this overload only participates in overload resolution if all of this holds:
std::same_as<std::remove_cvref_t<UTuple>, std::tuple>isfalse,std::remove_cvref_t<UTuple>is not a specialization ofstd::ranges::subrange,sizeof...(Types)equalsstd::tuple_size_v<std::remove_cvref_t<UTuple>>,std::is_constructible_v<Ti, decltype(std::get<i>(std::forward<UTuple>(u)))>is true for alli, and- either:
sizeof...(Types)is not1, or- (when
Types...expands toT)std::is_convertible_v<UTuple, T>andstd::is_constructible_v<T, UTuple>are bothfalse.
- this constructor is defined as deleted if initializing any element that's a reference would bind it to a temporary object π
13) the implicitly-defined copy constructor. It initializes every element of the tuple with the matching element of other.
- it's
constexprif every operation it does isconstexpr. For the empty tuple,std::tuple<>, it isconstexprπ std::is_copy_constructible<Ti>::valuemust betruefor alliβ otherwise:- the behavior is undefined (until C++20)
- the program is ill-formed (since C++20)
14) the implicitly-defined move constructor. For every i, it initializes the ith element of the tuple with std::forward<Ui>(std::get<i>(other)).
- it's
constexprif every operation it does isconstexpr. For the empty tuple,std::tuple<>, it isconstexprβ¨ std::is_move_constructible<Ti>::valuemust betruefor alliβ otherwise:- the behavior is undefined (until C++20)
- this overload does not participate in overload resolution (since C++20)
15-28) exactly the same as (1-14), except each element is created with uses-allocator construction β meaning the Allocator object a gets passed as an extra argument to the constructor of every element for which std::uses_allocator<Ui, Alloc>::value is true. no cap, it's the same vibe just with an allocator along for the ride π«Ά
π PARAMETERS
argsβ values used to initialize each element of the tupleotherβ the tuple of values used to initialize each element of the tuplepβ the pair of values used to initialize both elements of the 2-tupleuβ the tuple-like object of values used to initialize each element of the tupleaβ the allocator to use in uses-allocator construction
π NOTES
Conditionally-explicit constructors are the moment β they let you construct a tuple in a copy-initialization context using list-initialization syntax:
std::tuple<int, int> foo_tuple()
{
// return {1, -1}; // Error before N4387
return std::make_tuple(1, -1); // Always works
}
heads up bestie β if any element of the list isn't implicitly convertible to the corresponding element of the target tuple, the constructors become explicit:
using namespace std::chrono;
void launch_rocket_at(std::tuple<hours, minutes, seconds>);
launch_rocket_at({hours(1), minutes(2), seconds(3)}); // OK
launch_rocket_at({1, 2, 3}); // Error: int is not implicitly convertible to duration
launch_rocket_at(std::tuple<hours, minutes, seconds>{1, 2, 3}); // OK
π EXAMPLE
// Run this code
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <vector>
// helper function to print a vector to a stream
template<class Os, class T>
Os& operator<<(Os& os, std::vector<T> const& v)
{
os << '{';
for (auto i{v.size()}; const T& e : v)
os << e << (--i ? "," : "");
return os << '}';
}
template<class T>
void print_single(T const& v)
{
if constexpr (std::is_same_v<T, std::decay_t<std::string>>)
std::cout << std::quoted(v);
else if constexpr (std::is_same_v<std::decay_t<T>, char>)
std::cout << "'" << v << "'";
else
std::cout << v;
}
// helper function to print a tuple of any size
template<class Tuple, std::size_t N>
struct TuplePrinter
{
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N - 1>::print(t);
std::cout << ", ";
print_single(std::get<N - 1>(t));
}
};
template<class Tuple>
struct TuplePrinter<Tuple, 1>
{
static void print(const Tuple& t)
{
print_single(std::get<0>(t));
}
};
template<class... Args>
void print(std::string_view message, const std::tuple<Args...>& t)
{
std::cout << message << " (";
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
std::cout << ")\n";
}
// end helper function
int main()
{
std::tuple<int, std::string, double> t1;
print("Value-initialized, t1:", t1);
std::tuple<int, std::string, double> t2{42, "Test", -3.14};
print("Initialized with values, t2:", t2);
std::tuple<char, std::string, int> t3{t2};
print("Implicitly converted, t3:", t3);
std::tuple<int, double> t4{std::make_pair(42, 3.14)};
print("Constructed from a pair, t4:", t4);
// given Allocator my_alloc with a single-argument constructor
// my_alloc(int); use my_alloc(1) to allocate 5 ints in a vector
using my_alloc = std::allocator<int>;
std::vector<int, my_alloc> v{5, 1, my_alloc{/* 1 */}};
// use my_alloc(2) to allocate 5 ints in a vector in a tuple
std::tuple<int, std::vector<int, my_alloc>, double> t5
{std::allocator_arg, my_alloc{/* 2 */}, 42, v, -3.14};
print("Constructed with allocator, t5:", t5);
}
Possible output:
Value-initialized, t1: (0, "", 0)
Initialized with values, t2: (42, "Test", -3.14)
Implicitly converted, t3: ('*', "Test", -3)
Constructed from a pair, t4: (42, 3.14)
Constructed with allocator, t5: (42, {1,1,1,1,1}, -3.14)
π©Ή DEFECT REPORTS
These are the behavior-changing defect reports that got applied retroactively to already-published C++ standards (yes, time travel is real in the committee π«):
- LWG 2510 Β· applied to C++11 Β· as published: the default constructor was implicit β made conditionally-explicit
- LWG 3121 Β· applied to C++11 Β· as published: the constructor of 1-tuple might recursively check the constraints; the
allocator_arg_targument brought ambiguity β furtherly constrained the constructor - LWG 3158 Β· applied to C++11 Β· as published: the uses-allocator constructor corresponding to the default constructor was implicit β made conditionally-explicit
- LWG 3211 Β· applied to C++11 Β· as published: whether the default constructor of
tuple<>is trivial was unspecified β require to be trivial - N4387 Β· applied to C++11 Β· as published: some constructors were
explicit, preventing useful behavior β most constructors made conditionally-explicit - LWG 4045 Β· applied to C++23 Β· as published: the tuple-like constructor may potentially create dangling references β made defined as deleted
π SEE ALSO
operator=β assigns the contents of one tuple to another (public member function)make_tuple(C++11) β creates a tuple object of the type defined by the argument types (function template)tie(C++11) β creates a tuple of lvalue references or unpacks a tuple into individual objects (function template)forward_as_tuple(C++11) β creates a tuple of forwarding references (function template)constructorβ constructs new pair (public member function ofstd::pair<T1,T2>)
okay that's the whole page bestie, you ate that π β¨ this one's straight from cppreference.com, dated 2024.06.10 β go forth and construct your tuples with main character energy ππ¦π
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms