Add etl::apply (#1509)

Fixes: #1272

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Roland Reichwein 2026-07-16 10:15:24 +02:00 committed by GitHub
parent ea8eda0147
commit 38f7318a85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 130 additions and 0 deletions

View File

@ -249,3 +249,21 @@ template <typename T, typename... Types>
ETL_CONSTEXPR14
const T&& get(const tuple<Types...>&&);
```
---
```cpp
template <typename TFunction, typename TTuple>
ETL_CONSTEXPR14
auto apply(TFunction&& f, TTuple&& t);
```
Invokes the callable object `f` (via `etl::invoke`) with the elements of the tuple `t` expanded as its arguments. Equivalent to `std::apply`.
```cpp
int add(int a, int b, int c) { return a + b + c; }
auto t = etl::make_tuple(1, 2, 3);
int sum = etl::apply(add, t); // sum == 6
```

View File

@ -39,6 +39,7 @@ SOFTWARE.
#endif
#include "functional.h"
#include "invoke.h"
#include "nth_type.h"
#include "type_list.h"
#include "type_traits.h"
@ -934,6 +935,35 @@ namespace etl
return tuple<TTypes&&...>(etl::forward<TTypes>(args)...);
}
namespace private_tuple
{
//**********************************
// Helper for apply.
// Invokes the callable with the tuple elements expanded via the index sequence.
// Uses an unqualified 'get' so that argument-dependent lookup finds the
// appropriate overload for etl::tuple, etl::array, std::tuple, std::pair, etc.
//**********************************
template <typename TFunction, typename TTuple, size_t... Indices>
ETL_CONSTEXPR14 auto apply_impl(TFunction&& f, TTuple&& t, etl::index_sequence<Indices...>)
-> decltype(etl::invoke(etl::forward<TFunction>(f), get<Indices>(etl::forward<TTuple>(t))...))
{
return etl::invoke(etl::forward<TFunction>(f), get<Indices>(etl::forward<TTuple>(t))...);
}
} // namespace private_tuple
//***************************************************************************
/// Invokes the callable object 'f' with the elements of the tuple 't' as
/// arguments. Equivalent to std::apply.
//***************************************************************************
template <typename TFunction, typename TTuple>
ETL_CONSTEXPR14 auto apply(TFunction&& f, TTuple&& t)
-> decltype(private_tuple::apply_impl(etl::forward<TFunction>(f), etl::forward<TTuple>(t),
etl::make_index_sequence<etl::tuple_size<etl::remove_reference_t<TTuple>>::value>{}))
{
return private_tuple::apply_impl(etl::forward<TFunction>(f), etl::forward<TTuple>(t),
etl::make_index_sequence<etl::tuple_size<etl::remove_reference_t<TTuple>>::value>{});
}
namespace private_tuple
{
//**********************************

View File

@ -76,6 +76,32 @@ namespace
int i;
};
//*********************************
int apply_sum(int a, int b, int c)
{
return a + b + c;
}
//*********************************
struct Summer
{
int operator()(int a, int b) const
{
return a + b;
}
};
//*********************************
struct Accumulator
{
int total;
void add(int a, int b)
{
total = a + b;
}
};
SUITE(test_tuple)
{
//*************************************************************************
@ -930,5 +956,61 @@ namespace
CHECK_EQUAL(1, i);
CHECK_EQUAL(std::string("2"), d.value);
}
//*************************************************************************
TEST(test_apply_free_function)
{
etl::tuple<int, int, int> t(1, 2, 3);
CHECK_EQUAL(6, etl::apply(apply_sum, t));
}
//*************************************************************************
TEST(test_apply_function_object)
{
etl::tuple<int, int> t(10, 20);
CHECK_EQUAL(30, etl::apply(Summer(), t));
}
//*************************************************************************
#if ETL_USING_CPP11
TEST(test_apply_lambda)
{
etl::tuple<int, int, int> t(2, 3, 4);
int result = etl::apply([](int a, int b, int c) { return a * b * c; }, t);
CHECK_EQUAL(24, result);
}
#endif
//*************************************************************************
TEST(test_apply_member_function)
{
Accumulator acc = {0};
etl::apply(&Accumulator::add, etl::make_tuple(&acc, 5, 7));
CHECK_EQUAL(12, acc.total);
}
//*************************************************************************
TEST(test_apply_rvalue_tuple)
{
CHECK_EQUAL(6, etl::apply(apply_sum, etl::make_tuple(1, 2, 3)));
}
//*************************************************************************
#if ETL_USING_CPP11
TEST(test_apply_empty_tuple)
{
etl::tuple<> t;
int result = etl::apply([]() { return 42; }, t);
CHECK_EQUAL(42, result);
}
#endif
}
} // namespace