std::apply
| Defined in header <tuple>
|
||
template< class F, class Tuple >
constexpr decltype(auto) apply( F&& f, Tuple&& t );
|
(since C++17) (until C++23) |
|
template< class F, /*tuple-like*/ Tuple >
constexpr decltype(auto) apply( F&& f, Tuple&& t )
noexcept(/* see below */);
|
(since C++23) (until C++26) |
|
template< class F, /*tuple-like*/ Tuple >
constexpr std::apply_result_t<F, Tuple> apply( F && f , Tuple && t )
noexcept(std::is_nothrow_applicable_v<F, Tuple>);
|
(since C++26) | |
Invoke the Callable object f with the elements of t as arguments.
Given the exposition-only function apply-impl defined as follows:
template<class F,class Tuple, std::size_t... I>
constexpr decltype(auto)
apply-impl(F&& f, Tuple&& t, std::index_sequence<I...>) // exposition only
{
return INVOKE(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
The effect is equivalent to:
return apply-impl(std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size_v<std::decay_t<Tuple>>>{});
.
Parameters
| f | - | Callable object to be invoked |
| t | - | tuple whose elements to be used as arguments to f
|
Return value
The value returned by f.
Exceptions
|
(none) |
(until C++23) |
|
noexcept specification:
where
|
(since C++23) (until C++26) |
|
noexcept specification:
|
(since C++26) |
Notes
|
|
(until C++23) |
|
|
(since C++23) |
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_lib_apply |
201603L |
(C++17) | std::apply
|
202506L |
(C++26) | std::apply changes: std::apply_result, std::is_applicable and std::is_nothrow_applicable
|
Example
#include <iostream>
#include <tuple>
#include <utility>
constexpr int add(int first, int second) { return first + second; }
template<typename T>
constexpr T add_generic(T first, T second) { return first + second; }
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::tuple<Ts...>& theTuple)
{
std::apply
(
[&os](const Ts&... tupleArgs)
{
os << '[';
std::size_t n{0};
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
os << ']';
}, theTuple
);
return os;
}
template<class Func, class Tuple>
concept applicable = requires (Func&& func, Tuple&& args) {
std::apply(std::forward<Func>(func), std::forward<Tuple>(args));
};
auto func = [](){};
auto args = std::make_tuple(8);
#if __cpp_lib_apply >= 202506L
static_assert(!applicable<decltype(func), decltype(args)>); // OK
#else
#warning applicable<decltype(func), decltype(args)> is ill-formed
#endif
int main()
{
static_assert(std::apply(add, std::pair(1, 2)) == 3);
// Error: can't deduce the function type
// std::apply(add_generic, std::make_pair(2.0f, 3.0f));
auto add_lambda = [](auto first, auto second) { return first + second; };
static_assert(std::apply(add_lambda, std::pair(2.0f, 3.0f)) == 5.0f);
std::tuple myTuple{25, "Hello", 9.31f, 'c'};
std::cout << myTuple << '\n';
}
Possible output:
[25, Hello, 9.31, c]
