JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
Loading...
Searching...
No Matches
tuple.h File Reference

Implementation of POD-compatible tuple, pair and array bindings. More...

#include <tuple>
#include <utility>
#include <type_traits>
#include <iostream>
#include "jh/pods/pod_like.h"
#include "jh/pods/pair.h"
#include "jh/pods/array.h"

Go to the source code of this file.

Classes

struct  jh::pod::tuple< Ts >
 POD-compatible tuple type supporting structured bindings and tuple-like utilities. More...
struct  std::tuple_size< jh::pod::tuple< Ts... > >
struct  std::tuple_element< I, jh::pod::tuple< Ts... > >
struct  std::tuple_size< jh::pod::pair< T1, T2 > >
struct  std::tuple_element< I, jh::pod::pair< T1, T2 > >
struct  std::tuple_size< jh::pod::array< T, N > >
struct  std::tuple_element< I, jh::pod::array< T, N > >

Namespaces

namespace  jh::pod
 Aggregated entry point for Plain-Old-Data and layout-stable value utilities.

Functions

template<std::size_t I, typename... Ts>
constexpr decltype(auto) jh::pod::get (tuple< Ts... > &t) noexcept
template<std::size_t I, typename... Ts>
constexpr auto jh::pod::get (const tuple< Ts... > &t) noexcept
template<std::size_t I, typename T1, typename T2>
constexpr decltype(auto) jh::pod::get (jh::pod::pair< T1, T2 > &p) noexcept
template<std::size_t I, typename T1, typename T2>
constexpr decltype(auto) jh::pod::get (const jh::pod::pair< T1, T2 > &p) noexcept
template<std::size_t I, typename T, std::uint16_t N>
constexpr decltype(auto) jh::pod::get (jh::pod::array< T, N > &a) noexcept
template<std::size_t I, typename T, std::uint16_t N>
constexpr decltype(auto) jh::pod::get (const jh::pod::array< T, N > &a) noexcept
template<typename... Ts>
constexpr auto jh::pod::make_tuple (Ts &&... args) noexcept
 Constructs a POD-compatible tuple from given arguments.
template<typename... Ts>
constexpr bool jh::pod::operator== (const tuple< Ts... > &lhs, const tuple< Ts... > &rhs) noexcept
template<typename... Ts>
constexpr bool jh::pod::operator!= (const tuple< Ts... > &lhs, const tuple< Ts... > &rhs) noexcept

Detailed Description

Implementation of POD-compatible tuple, pair and array bindings.

This header defines jh::pod::tuple<Ts...> and its interoperability with std::tuple_size and std::tuple_element. It also provides jh::pod::get overloads for tuple, pair, and array so that they can participate in structured bindings and tuple-like generic programming.

The implementation is based on recursive aggregate composition: every element is stored inside a trivial wrapper tuple_field<I, T>, and each layer of tuple_impl provides one field and a sublayer for the rest. This ensures that the resulting type remains a true POD while supporting element-wise access.

Design Philosophy & Principles

The jh::pod::tuple in version 1.3.4 and later is a true POD-based tuple, replacing the transitional implementation used between 1.3.0-1.3.3.

It achieves std::tuple-like behavior — supporting make_tuple, get<>, packing, and unpacking — through composition instead of inheritance. Each element is recursively composed inside a tuple_field<I, T> wrapper, ensuring complete triviality and standard layout.

Because every layer is a deducible aggregate, the resulting tuple is a pure POD type. Optimizers can often treat get<I>(tuple) as a direct offset-based access into a contiguous memory block. In effect, the memory layout of jh::pod::tuple is equivalent to a manually defined POD struct with unnamed, ordered fields.

Note that this version uses ADL-based access: get<I>(tuple) rather than tuple.get<I>().

Value and Reference Unpacking

  • When unpacked as auto or const auto&, elements are accessed by value. This design prevents unsafe aliasing; const_cast tricks cannot modify internal data.
  • When unpacked as auto&, elements are accessed by reference and can be safely modified.

These semantics provide safe and predictable structured bindings fully aligned with standard tuple-like behavior while maintaining strict POD guarantees.

Example

#include <jh/pod>
using namespace jh::pod;
int main() {
auto t = make_tuple(7, 3.14f);
std::cout << t << std::endl; // prints: (7, 3.14)
}
Aggregated entry point for Plain-Old-Data and layout-stable value utilities.
Definition pod:67
constexpr auto make_tuple(Ts &&... args) noexcept
Constructs a POD-compatible tuple from given arguments.
Definition tuple.h:301
Forward-aggregator header for jh::pod — the Plain-Old-Data utilities.

Important Notes on Initialization

Clang (C++20 and later) fully supports direct aggregate initialization:

jh::pod::tuple<int, float> t{7, 3.14f}; // valid in Clang
POD-compatible tuple type supporting structured bindings and tuple-like utilities.
Definition tuple.h:198

However, GCC may reject the same form with an error such as "too many initializers". This is due to stricter handling of aggregate inheritance.

Warning
For GCC (especially ≤ 13), prefer one of the following forms:
// Explicit nested braces
jh::pod::tuple<int, float> t{{ {7}, {{3.14f}, {}} }};
// or, recommended portable helper
auto t = jh::pod::make_tuple(7, 3.14f);
Note
The output operator (operator<<) for tuple, pair and array is provided in <jh/pods/stringify.h>. After including it, all these POD containers can be directly printed using std::ostream.
See also
jh::pod::pair
jh::pod::array