One, what is a tuple
Tuples are not something new, there are tuples in math, Python language, and C + + that we're talking about today.
To put it simply, a tuple is a set of things, for example, when it comes to algebraic topology, the topological space X and one of the dots X are often used as a pair (x, x), which is actually a tuple, and the coordinates of a point can also be considered as a tuple. The tuple (tuple) in C + + is this way:
Std::tuple<int, std::string> tu{2, "12iop"};
A tuple can contain different types of members, for example, the above TU contains an int and a string.
Second, use
Before we examine the source code, we must first know its usage.
To use tuple, include the header file <tuple>:
Tuple is actually a class template with variable parameters that, when used, is specific by passing in several parameters.
struct point
{
int x;
int y;
};
void Main ()
{
std::tuple<int, std::string> t1{1, "Qwer"};//a tuple constexpr std consisting of int and strings
:: Tuple<int, void*> t2{1,nullptr}; A tuple std::tuple<int composed of int and void*
, point> t3{1,{20,89};//a tuple of int and point structures
<int, Char, std::string> t4{1, ' t ', ' qwer '}; A tuple consisting of int, char, string
In the code above, I decorated the T2 with constexpr, which is exactly right, and the Std::tuple constructor is constexpr.
Gets the value in the tuple, using the std::get. This is not a function, it's a function template, we need to pass in a variable of type size_t, or pass in a type, telling it what type of member we need to take out of a tuple.
struct point
{
int x;
int y;
};
void Main ()
{
std::tuple<int, std::string> t1{1, "Qwer"};
constexpr std::tuple<int, void*> t2{10,nullptr};
Std::tuple<int, point> t3{1,{20,89};
Std::tuple<int, Char, std::string> t4{1, ' t ', ' qwer '};
Std::cout << std::get<0> (t1) << Std::endl; 1
constexpr int n2 = std::get<0> (t2);
Std::cout << n2 << Std::endl; The
auto s = std::get<char> (T4);
Std::cout << s << std::endl; T
}
Std::get is also constexpr, so N2 is also a compile-time constant.
We get the s from the get<char>, which is a variable of type char. Std::get<t> can be obtained from tuple to the first member of type T.
Tuple can also compare equality with "= =" and "!=":
Std::tuple<int, std::string> t5{1, "Qwer"};
if (T1 = = T5)
{
std::cout << "= =" << Std::endl;
}
It is not the main content of this article to introduce the usage of tuple, so this concludes. Interested students can access the information themselves.
Next, it is time to look at the source code.
Third, the source code analysis
Tuple is a class template with variable parameters:
Template<typename. _types>
class tuple;
This is a declaration of the class template.
Next, an empty tuple with zero number of parameters is implemented.
3.1 tuple<>
struct allocator_arg_t
{};
Template<>
class tuple<>
{public
:
typedef tuple<> _MYT;
constexpr tuple () noexcept
{}
template<typename _alloc> tuple
(allocator_arg_t, const _alloc& ) noexcept
{}
constexpr tuple (const tuple&) noexcept
{}
template<class _alloc>
Tuple (allocator_arg_t, const _alloc&, const _myt&) noexcept
{}
void Swap (_myt&) noexcept
{ }
constexpr bool _equals (const _myt&) const noexcept
{return
true;
}
constexpr bool _less (const _myt&) const noexcept
{return
false;
}
;
allocator_arg_t is an empty structure, and it doesn't matter for the moment. _myt is tuple<> himself, so it is easier to write.
Tuple<> defines empty constructors and copy constructors (empty tuple have nothing to do).
The member function swap is used to exchange content with another tuple<>, because there is nothing to swap, and the function body is certainly empty.
_equals is used to determine whether two tuple<> are equal, and it returns true, which is obvious (all tuple<> are the same).
_less from the function name to compare size, but what if you encounter a type that does not have the overload <? temporarily ignore it.
With the definition of an empty tuple, you can define a tuple that is not empty.
3.2 Non-empty tuple
Template<class _this,
class ... _rest>
class tuple<_this, _rest...>
: Private tuple<_rest ...>
{
//content
}
The tuple private of the N (>0) element inherits the tuple of the n-1 element. Clearly this is a recursive definition that will eventually be recursive to Tuple<>, and tuple<> is already well defined.
For example, Tuple<int, Char, short> private inherited Tuple<char, Short>, and Tuple<char, short> and private inheritance tuple<short> Tuple<short> Private inherited the tuple<>. Because private inheritance can implement the "has-a" feature, such a way can combine different types of objects together. The following figure:
So, how does tuple store the elements?
Template<class _this,
class ... _rest>
class tuple<_this, _rest...>
: Private tuple<_rest ...>
{//recursive tuple definition public
:
typedef _this _THIS_TYPE;
typedef tuple<_this, _rest...> _MYT;
typedef tuple<_rest...> _mybase;
static const size_t _mysize = 1 + sizeof ... (_rest);
_tuple_val<_this> _myfirst; Stored elements
}
Originally, it has a member called _myfirst, it is used to store _this type of variable. You will see that the type of _myfirst is not _this but _tuple_val<_this> in fact, _tuple_val is a class template, its code is not expanded here, in short, its role is to store a variable in the Tuple. _myfirst._val is the real element.
This tuple stores only one element, the type is _rest ... Other elements exist in the base class _mybase i.e. tuple<_rest...>. We still take Tuple<int, Char, short> for example, Tuple<int, char, short> store an int, have base class Tuple<char, short>; and tuple< Char, short> stores a char, has a base class tuple<short>;tuple<short> stores a short, has a base class Tuple<>;tuple no base class, and does not store any elements.
3.3 Constructors
Tuple's constructor is nothing to say, it is to initialize _myfirst and _mybase, of course, _mybase also have to do a process, until tuple<>.
Constexpr tuple (): _mybase (), _myfirst ()
{}
constexpr explicit tuple (const _this& _this_arg,
const _ Rest& ... _rest_arg)
: _mybase (_rest_arg ...),
_myfirst (_this_arg)
{}
tuple (const _myt&) = default;
Tuple (_myt&&) = default;
It also provides a default copy constructor and a move constructor (mobile semantics is a new feature in C++11, please refer to the information yourself). In fact, it also has a lot of constructors, write a very lively, nothing but is in different ways for it to assign initial value, so omitted.
3.4 Partial member functions
Tuple overloaded the assignment symbol (=) so that the tuple is assignable
Template<class _other>
_myt& operator= (const tuple<_other...>& _right)
{//Assign By copying same size tuple
_myfirst._val = _right._myfirst._val;
_get_rest () = _right._get_rest ();
return (*this);
}
The assignment symbol returns the reference to the left, which is consistent with the built-in type of C + +. _get_rest is a tuple member function that takes out the elements except _myfirst.
Next is the member function _equals,
Template<class _other>
constexpr bool _equals (const tuple<_other...>& _right) const
{
Static_assert (_mysize = = sizeof ... (_other), "Comparing tuple to object with different size");
return (_myfirst._val = = _right._myfirst._val && _mybase::_equals (_right._get_rest ()));
}
A static assertion is made, and a compile-time error is raised if the number of elements in the two tuple is not the same. If the corresponding type cannot be compared with = =, a compile-time error can also occur when the template is tuple<std::string, for example, int> and Tuple<int, char> compared because std:: string and int cannot be compared with = =.
The _get_rest mentioned above are here:
_mybase& _get_rest () noexcept
{return
(*this);
}
constexpr Const _mybase& _get_rest () const noexcept
{return
(*this);
}
It returns a reference to the base class. Although the type of *this is _MYT, it is OK to do so based on C + + syntax (you can assign a reference to a derived class to a reference to a base class).
The above is the C + + standard library tuple (tuple) source analysis of all the content, I hope to help you learn.