hyperion::mpl::Pair#

group pair

Hyperion provides mpl::Pair as a metaprogramming type for storing, communicating, working with, and operating on pairs of types or values.

Example#

#include <hyperion/mpl/pair.h>

using namespace hyperion::mpl;

constexpr auto add_const = [](MetaPair auto pair) noexcept {
    return make_pair(pair.make_first().as_const(),
                     pair.make_second().as_const());
};

constexpr auto pair = Pair<int, double>{};
constexpr auto constified = pair.apply(add_const);

static_assert(constified == Pair<const int, const double>{});

Functions

template<typename TLHSFirst, typename TLHSSecond, typename TRHSFirst, typename TRHSSecond>
constexpr auto operator==(const Pair<TLHSFirst, TLHSSecond> &lhs, const Pair<TRHSFirst, TRHSSecond> &rhs) noexcept -> bool#

Equality comparison operator between two Pair specializations.

Checks that lhs and rhs both represent the same metaprogramming types and values.

Example#

constexpr auto first = Pair<int, Value<1, std::uint32_t>>{};
constexpr auto second = Pair<int, Value<1, std::uint64_t>>{};

static_assert(first == second);

Template Parameters:
  • TLHSFirst – The first type of the left-hand Pair of the comparison

  • TLHSSecond – The second type of the left-hand Pair of the comparison

  • TRHSFirst – The first type of the right-hand Pair of the comparison

  • TRHSSecond – The second type of the right-hand Pair of the comparison

Parameters:
  • lhs – The left-hand Pair to compare

  • rhs – The right-hand Pair to compare with

Returns:

whether lhs represents the same metaprogramming types and values as rhs

template<typename TFirst, typename TSecond>
constexpr auto make_pair(TFirst &&first, TSecond &&second) noexcept -> Pair<detail::convert_to_raw_t<TFirst>, detail::convert_to_raw_t<TSecond>>#

Constructs an mpl::Pair representing the types of the given arguments.

If TFirst or TSecond are metaprogramming types, first converts them to their raw type before storing in the Pair. (e.g. if either are mpl::Type<some_type>, the returned pair would be Pair<some_type1, some_type2>, not Pair<Type<some_type1>, Type<some_type2>>).

This overload does not accept reference qualified parameters.

Requirements#

  • TFirst is not reference qualified

  • TSecond is not reference qualified

Example#

constexpr auto pair = make_pair(decltype_<int>(), decltype_<double>());
static_assert(pair == Pair<int, double>{});

Template Parameters:
  • TFirst – The first type to store in a Pair

  • TSecond – The second type to store in a Pair

Parameters:
  • first – The first value to store the type of

  • second – The second value to store the type of

Returns:

a Pair representing the raw types of TFirst and TSecond

template<typename TFirst, typename TSecond>
struct Pair#
#include <hyperion/mpl/pair.h>

Pair is Hyperion’s metaprogramming type for operating on pairs of types or values.

Example#

#include <hyperion/mpl/pair.h>

using namespace hyperion::mpl;

constexpr auto add_const = [](MetaPair auto pair) noexcept {
    return make_pair(pair.make_first().as_const(),
                     pair.make_second().as_const());
};

constexpr auto pair = Pair<int, double>{};
constexpr auto constified = pair.apply(add_const);

static_assert(constified == Pair<const int, const double>{});

Template Parameters:
  • TFirst – The first type to store in the pair

  • TSecond – The second type to store in the pair

Public Types

using first = detail::convert_to_meta_t<TFirst>#

The first type to store in the pair, converted to the appropriate metaprogramming type.

If TFirst is a specialization of mpl::Type, mpl::Pair, or mpl::Value, this aliases to TFirst. Otherwise, wraps it in mpl::Type.

using second = detail::convert_to_meta_t<TSecond>#

The second type to store in the pair, converted to the appropriate metaprogramming type.

If TSecond is a specialization of mpl::Type, mpl::Pair, or mpl::Value, this aliases to TSecond. Otherwise, wraps it in mpl::Type.

Public Functions

template<typename TDelay = first>
inline constexpr auto make_first() const noexcept -> TDelay#

Returns an instance of first

Example#

constexpr auto first = Pair<int, double>{}.make_first();
static_assert(first == decltype_<int>());

Returns:

an instance of first

template<typename TDelay = second>
inline constexpr auto make_second() const noexcept -> TDelay#

Returns an instance of second

Example#

constexpr auto second = Pair<int, double>{}.make_second();
static_assert(second == decltype_<double>());

Returns:

an instance of second

template<template<typename> typename TMetaFunction>
inline constexpr auto apply() const noexcept -> detail::convert_to_meta_t<TMetaFunction<Pair>>#

Applies the template metafunction TMetaFunction to this Pair.

Applies TMetaFunction to this Pair, and returns the result as a metaprogramming type (a specialization of mpl::Type, mpl::Value, or mpl::Pair).

Requirements#

  • TMetaFunction must be instantiatable with this specialization of Pair (i.e. TMetaFunction<Pair> must be well-formed).

  • The specialization of TMetaFunction for Pair, TMetaFunction<Pair>, must be a metaprogramming type (i.e. it must be a MetaType, MetaValue, or MetaPair)

Example#

template<typename TType>
requires (!MetaPair<TType>)
struct add_one_or_const {
    using type = std::conditional_t<MetaValue<TType>,
                                    decltype(TType{} + 1_value),
                                    decltype(decltype_<TType>().as_const())>;
};

template<typename TPair>
struct add_one_or_const_to_pair {
    using first = typename add_one_or_const<typename TPair::first>::type;
    using second = typename add_one_or_const<typename TPair::second>::type;
};

static_assert(Pair<int, Value<1>>{}.apply<add_one_or_const_to_pair>()
              == Pair<const int, Value<2>>{});

Template Parameters:

TMetaFunction – The template metafunction to apply

Returns:

The result of applying TMetaFunction to this Pair, as a metaprogramming type

template<template<typename> typename TMetaFunction>
inline constexpr auto apply() const noexcept#

Applies the template metafunction TMetaFunction to the types represented in this Pair.

Applies TMetaFunction to first and second individually, returning the results together as a specialization of Pair. Applies TMetaFunction to each of first and second as if by make().template apply<TMetaFunction>(), where make is make_first or make_second, respectively.

Requirements#

  • TMetaFunction must not be instantiatable with this specialization of Pair. I.E. TMetaFunction<Pair> must not be well-formed (this is most easily achievable by adding a requirement clause of requires (!MetaPair<TType>) to your TMetaFunction, where TType is the type parameter of the template).

  • TMetaFunction must be applicable to both first and second. I.E., make().template apply<TMetaFunction>(), where make is make_first or make_second, respectively, must be well formed.

Example#

template<typename TType>
requires (!MetaPair<TType>)
struct add_one_or_const {
    using type = std::conditional_t<MetaValue<TType>,
                                    decltype(TType{} + 1_value),
                                    decltype(decltype_<TType>().as_const())>;
};

static_assert(Pair<int, Value<1>>{}.apply<add_one_or_const>()
              == Pair<const int, Value<2>>{});

Template Parameters:

TMetaFunction – The template metafunction to apply

Returns:

The result of applying TMetaFunction to this Pair, as a metaprogramming type

template<typename TFunction>
inline constexpr auto apply(TFunction &&func) const noexcept -> meta_result_t<TFunction, Pair>#

Applies the metafunction TFunction to this Pair.

Applies TFunction to this Pair, as if by std::forward<TFunction>(func)(Pair{}), and returns the resulting metaprogramming type.

Requirements#

Example#

constexpr auto add_one_or_const = [](MetaPair auto pair) noexcept {
    constexpr auto apply_to_inner = [](auto inner) noexcept {
        if constexpr(MetaType<decltype(inner)>) {
            return inner.as_const();
        }
        else if constexpr(MetaValue<decltype(inner)>) {
            return inner + 1_value;
        }
    };

    return make_pair(pair.make_first().apply(apply_to_inner),
                     pair.make_second().apply(apply_to_inner));
};

static_assert(Pair<int, Value<1>>{}.apply(add_one_or_const)
              == Pair<const int, Value<2>>{});

Template Parameters:

TFunction – The type of the metafunction to apply

Parameters:

func – The metafunction to apply

Returns:

The result of applying TFunction to this Pair

template<typename TFunction>
inline constexpr auto apply(TFunction &&func) const noexcept -> Pair<meta_result_t<TFunction, first>, meta_result_t<TFunction, second>>#

Applies the metafunction TFunction to the types represented in this Pair.

Applies TFunction to first and second individually, returning the results together as a specialization of Pair. Applies TFunction to each of first and second as if by make().apply(std::forward<TFunction>(func)), where make is make_first or make_second, respectively.

Requirements#

Example#

constexpr auto add_one_or_const = [](auto val) noexcept
    requires (!MetaPair<decltype(val)>)
{
    if constexpr(MetaType<decltype(val)>) {
        return val.as_const();
    }
    else if constexpr(MetaValue<decltype(val)>) {
        return val + 1_value;
    }
};

static_assert(Pair<int, Value<1>>{}.apply(add_one_or_const)
              == Pair<const int, Value<2>>{});

Template Parameters:

TFunction – The type of the metafunction to apply

Parameters:

func – The metafunction to apply

Returns:

The result of applying TFunction to the types represented in this Pair

template<template<typename> typename TPredicate>
inline constexpr auto satisfies() const noexcept -> detail::convert_to_meta_t<TPredicate<Pair>>#

Checks that this Pair satisfies the template metafunction predicate, TPredicate.

Checks that this Pair satisfies TPredicate and returns the result as an mpl:Value<result, bool>.

Requirements#

  • TPredicate must be instantiatable with this specialization of Pair (i.e. TPredicate<Pair> must be well-formed).

  • The specialization of TMetaFunction for Pair, TMetaFunction<Pair>, must be a MetaValue

  • The value of the specialization of TMetaFunction for Pair, TMetaFunction<Pair>::value, must be of type (possibly cv-ref qualified) bool

Example#

template<typename TType>
requires (!MetaPair<TType>)
struct is_one_or_const {
    static inline constexpr auto value = false;
};

template<typename TType>
requires MetaValue<TType>
struct is_one_or_const<TType> {
    static inline constexpr auto value = TType::value == 1;
};

template<typename TType>
requires MetaType<TType>
struct is_one_or_const<TType> {
    static inline constexpr auto value = std::is_const_v<typename TType::type>;
};

template<typename TPair>
struct is_one_or_const_in_pair {
    static inline constexpr auto value
        = is_one_or_const<typename TPair::first>::value
          && is_one_or_const<typename TPair::second>::value;
};

static_assert(Pair<int, Value<1>>{}.satisfies<is_one_or_const_in_pair>());

Template Parameters:

TPredicate – The template metafunction predicate to validate

Returns:

whether this Pair satisfies TPredicate, as an mpl::Value

template<template<typename> typename TPredicate>
inline constexpr auto satisfies() const noexcept#

Checks that the types represented by this Pair satisfy the template metafunction predicate, TPredicate.

Checks that first and second both satisfy TPredicate, and returns the result as an mpl:Value<result, bool>. Checks that first and second both satisfy TPredicate as if by make().template satisfies<TPredicate>() where make is make_first or make_second, respectively.

Requirements#

  • TPredicate must not be instantiatable with this specialization of Pair. I.E., TPredicate<Pair> must not be well-formed (this is most easily achievable by adding a requirement clause of requires (!MetaPair<TType>) to your TPredicate, where TType is the type parameter of the template).

  • TPredicate must be a template metafunction predicate capable of being satisfied by both first and second. I.E., TMetaFunction<first> and TMetaFunction<second> must be well-formed.

Example#

template<typename TType>
requires (!MetaPair<TType>)
struct is_one_or_const {
    static inline constexpr auto value = false;
};

template<typename TType>
requires MetaValue<TType>
struct is_one_or_const<TType> {
    static inline constexpr auto value = TType::value == 1;
};

template<typename TType>
requires MetaType<TType>
struct is_one_or_const<TType> {
    static inline constexpr auto value = std::is_const_v<typename TType::type>;
};

static_assert(Pair<int, Value<1>>{}.satisfies<is_one_or_const>());

Template Parameters:

TPredicate – The template metafunction predicate to validate

Returns:

whether this Pair satisfies TPredicate, as an mpl::Value

template<typename TPredicate>
inline constexpr auto satisfies(TPredicate &&predicate) const noexcept#

Checks that this Pair satisfies the metafunction predicate, predicate.

Checks that this Pair satisfies predicate and returns the result as an mpl:Value<result, bool>.

If predicate is a MetaPredicateOf<Pair>, invokes predicate with this Pair specialization and returns the result. Otherwise, checks if first and second separately satisfy predicate, and returns the boolean and of those results.

Example#

constexpr auto is_one_or_const = [](auto value) noexcept {
    if constexpr(MetaType<decltype(value)>) {
        return value.is_const();
    }
    else if constexpr(MetaValue<decltype(value)>) {
        return Value<decltype(value)::value == 1, bool>{};
    }
};

static_assert(Pair<int, Value<1>>{}.satisfies(is_one_or_const));

Template Parameters:

TPredicate – The metafunction predicate to validate

Returns:

whether this Pair satisfies predicate, as an mpl::Value

template<typename TFunction>
inline constexpr auto unwrap(TFunction &&func) const noexcept -> std::invoke_result_t<TFunction, first, second>#

Unwraps this Pair into first and second, and invokes func with them.

Decomposes this into its constituent first and second metaprogramming elements and invokes func, passing first and second as the invocation arguments, returning the result of the invocation.

Requirements#

  • func must be invocable with first, second

Example#

constexpr auto sum = [](MetaValue auto lhs, MetaValue auto rhs) noexcept {
    return lhs + rhs;
};

static_assert(Pair<Value<1>, Value<2>>{}.unpack(sum) == 3_value);

Template Parameters:

TFunction – the type of the function to invoke with first and second as arguments

Parameters:

func – the function to invoke with first and second as arguments

Returns:

The result of invoking func with first and second as arguments

template<std::size_t TIndex>
inline constexpr auto get() const noexcept#

Returns the metaprogramming type at TIndex of this Pair

If TIndex is 0, returns first. If TIndex is 1, returns second.

Requirements#

  • TIndex must be 0, or 1

Example#

constexpr auto first = Pair<int, double>{}.template get<0>();
static_assert(first == decltype_<int>());

Template Parameters:

TIndex – The index of the type to get

Returns:

The metaprogramming type at TIndex of this Pair

Note

This, combined with specializations of std::tuple_element and std::tuple_size enable structured binding destructuring of this pair into first and second individually, as in:

// we can't use structured bindings outside of function-scope, so we wrap our example
// in a `constexpr` function
constexpr auto example() {
    auto [first, second] = Pair<int, double>{};
    return first == decltype_<int>() && second == decltype_<double>();
}

static_assert(example());

template<std::size_t TIndex>
inline constexpr auto get() noexcept#

Returns the metaprogramming type at TIndex of this Pair

If TIndex is 0, returns first. If TIndex is 1, returns second.

Requirements#

  • TIndex must be 0, or 1

Example#

constexpr auto first = Pair<int, double>{}.template get<0>();
static_assert(first == decltype_<int>());

Template Parameters:

TIndex – The index of the type to get

Returns:

The metaprogramming type at TIndex of this Pair

Note

This, combined with specializations of std::tuple_element and std::tuple_size enable structured binding destructuring of this pair into first and second individually, as in:

// we can't use structured bindings outside of function-scope, so we wrap our example
// in a `constexpr` function
constexpr auto example() {
    auto [first, second] = Pair<int, double>{};
    return first == decltype_<int>() && second == decltype_<double>();
}

static_assert(example());