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
adl_apply.h File Reference

ADL-enabled universal tuple application utility — extends std::apply to arbitrary tuple-like structures, including user-defined proxies and view elements. More...

#include "jh/conceptual/tuple_like.h"
#include <functional>
#include <tuple>
#include <utility>
#include <type_traits>

Go to the source code of this file.

Namespaces

namespace  jh::meta
 Aggregated entry point for compile-time metaprogramming utilities.

Functions

template<class F, class T, size_t... I>
constexpr decltype(auto) jh::meta::adl_apply_impl (F &&f, T &&t, std::index_sequence< I... >)
 Internal implementation helper for jh::meta::adl_apply.
template<class F, jh::concepts::tuple_like T>
constexpr decltype(auto) jh::meta::adl_apply (F &&f, T &&t) noexcept(noexcept(adl_apply_impl(std::forward< F >(f), std::forward< T >(t), std::make_index_sequence< std::tuple_size_v< std::remove_cvref_t< T > > >{})))
 ADL-enabled universal apply for tuple-like objects.

Detailed Description

ADL-enabled universal tuple application utility — extends std::apply to arbitrary tuple-like structures, including user-defined proxies and view elements.

Author
JeongHan-Bae <mastropseudo@gmail.com>

The jh::meta::adl_apply function is a generalized alternative to std::apply that allows invocation of callables on both standard and user-defined tuple-like objects. It performs unqualified lookup for get to enable Argument-Dependent Lookup (ADL), thereby extending support beyond the standard tuple family.

Motivation

The C++ standard restricts std::apply to built-in tuple-like types (std::tuple, std::pair, std::array), because std::apply directly calls std::get. However:

  • User-defined get functions cannot reside in std namespace;
  • std::get cannot be specialized for non-standard types;
  • C++ nevertheless permits defining tuple_size and tuple_element for custom structures;
  • Thus, a large class of tuple-like proxies (e.g., jh::ranges::zip_reference_view supporting jh::ranges::zip_view) as well as a lot of third-party defined tuple-like proxies cannot work with std::apply.

jh::meta::adl_apply bridges this semantic gap by employing unqualified get calls, so both standard and ADL-visible overloads participate in lookup. It effectively becomes a universal apply for all tuple-like types.

Supported types

  • Standard tuple-likes: std::tuple, std::pair, std::array.
  • User-defined tuple-likes: types modeling jh::concepts::tuple_like (i.e., define tuple_size / tuple_element and expose ADL-visible get).
  • Proxy-based ranges: view elements such as jh::ranges::zip_reference_view.

Usage example

namespace demo {
struct proxy { int i; double d; };
// Define ADL-visible get<I> overloads
template<std::size_t I>
decltype(auto) get(proxy &p) noexcept {
if constexpr (I == 0) return (p.i);
else return (p.d);
}
}
namespace std {
template<>
struct std::tuple_size<proxy> : std::integral_constant<size_t, 2> {};
template<size_t I>
struct std::tuple_element<I, proxy> {
using type = std::conditional_t<I == 0, int, double>;
};
}
demo::proxy p{1, 3.14};
// Works for both std and ADL get<I>
jh::meta::adl_apply([](auto &&x, auto &&y) {
std::cout << x << ", " << y << '\n';
}, p);
constexpr decltype(auto) adl_apply(F &&f, T &&t) noexcept(noexcept(adl_apply_impl(std::forward< F >(f), std::forward< T >(t), std::make_index_sequence< std::tuple_size_v< std::remove_cvref_t< T > > >{})))
ADL-enabled universal apply for tuple-like objects.
Definition adl_apply.h:217
Definition flatten_proxy.h:180

Behavior summary

  • Performs unqualified lookup for get — enabling ADL discovery.
  • Expands index sequence from std::tuple_size_v<T>.
  • Perfect-forwards both callable and tuple object.
  • Propagates noexcept and constexpr guarantees.

Integration example (with collect)

auto result = range
constexpr detail::enumerate_fn enumerate
The user-facing enumerate adaptor.
Definition enumerate.h:149
constexpr collect_fn< C > collect
Global instance of the collect adaptor.
Definition collect.h:375

In this example, enumerate() yields a tuple-like proxy containing an index and reference. collect internally employs jh::meta::adl_apply to unpack the proxy into actual std::pair<size_t, std::string> values via emplace_back().

Design rationale

  • Language conformance: avoids illegal specialization of std::get.
  • ADL openness: honors user-defined get functions.
  • Compile-time safety: constrained by jh::concepts::tuple_like.
  • Zero-overhead abstraction: identical assembly as std::apply for STL tuples.

See also
jh::concepts::tuple_like
std::apply
Version
1.3.x
Date
2025