It is known that std::tuple
(since c++11) is a generalization of std::pair
. However, they exhibit some slight differences in some cases.
Consider the following code:
struct dummy {}; int main() { std::cout << sizeof(int) << std::endl; std::cout << sizeof(std::pair<int, dummy>) << std::endl; std::cout << sizeof(std::tuple<int, dummy>) << std::endl; }
When compiling with g++ and libstdc++, the output might be 4, 8, 4. Why std::tuple<int, dummy>
takes less space than std::pair<int, dummy>
?
This is a nontrivial problem. Unlike C, empty struct
s (and class
es) are supported in C++; however, they must take nonzero space (typically 1 byte) so that every instance of the empty struct has unique address.
The typical implementation of pair<T1, T2>
is simply a struct with two members T1 first
and T2 second
. For std::pair<int, dummy>
, it contains two members, of type int
and dummy
respectively. The total size is 5, however, due to padding, the pair actually takes 8 bytes.
Since the number of members of a tuple
is variable, its implementation is more complex. In libstdc++, the tuple
is implemented as double inheritance: _Tuple_impl<id, X, Y, Z>
inherits _Head_base<id, X>
and _Tuple_impl<id + 1, Y, Z>
, and _Head_base<id, X>
again inherits X
if X
is an empty non-final struct. In such case, _Head_base<id, X>
is also empty and thus the compiler is allowed to perform Empty Base Optimization (EBO), that is, the empty base need not take up any space. That’s why std::pair<int, dummy>
takes only 4 bytes.