utility_apply
utility_apply (튜플 요소를 인자로 함수 호출)
이 페이지는 C++ 표준 라이브러리의 std::apply 함수 템플릿에 대해 설명해요. std::apply는 주어진 튜플의 요소들을 풀어서 호출 가능한 객체의 인자로 전달해요. C++17에서 도입되었고, 이후 버전에서 제약과 예외 명세가 개선되었어요.
출처: cppreference
본문
<tuple> 헤더에 정의되어 있어요. 호출 가능한 객체 f를 튜플 t의 요소들을 인자로 하여 호출해요.
노출 전용 함수 apply-impl이 다음과 같이 정의된다고 할 때:
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 ))...);
}
효과는 다음 표현식과 동등해요:
return apply-impl ( std :: forward < F > ( f ), std :: forward < Tuple > ( t ),
std :: make_index_sequence < std :: tuple_size_v < std :: decay_t < Tuple >>> {});
매개변수
| 매개변수 | 설명 |
|---|---|
f |
호출할 호출 가능한 객체 |
t |
f의 인자로 사용할 요소들을 가진 튜플 |
반환값
f가 반환한 값이에요.
예외
| 버전 | 예외 명세 |
|---|---|
| (C++23 이전) | 없음 |
| (C++23~C++26) | noexcept 명세: noexcept(noexcept(std::invoke(std::forward<F>(f), std::get<Is>(std::forward<Tuple>(t))...))) 여기서 Is...는 팩 0, 1, ..., std::tuple_size_v<std::remove_reference_t<Tuple>> - 1을 나타내요. |
| (C++26 이후) | noexcept 명세: noexcept(std::is_nothrow_applicable_v<F, Tuple>) |
참고 사항
| 버전 | 내용 |
|---|---|
| (C++23 이전) | Tuple이 반드시 std::tuple일 필요는 없고, std::get과 std::tuple_size를 지원하는 모든 타입이 될 수 있어요. 특히 std::array와 std::pair도 사용할 수 있어요. |
| (C++23 이후) | Tuple은 튜플-유사(tuple-like) 타입으로 제약되어요. 즉, 그 안의 각 타입은 std::tuple의 특수화이거나 tuple-like 모델을 만족하는 다른 타입(예: std::array, std::pair)이어야 해요. |
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_lib_apply |
201603L |
(C++17) | std::apply |
202506L |
(C++26) | std::apply 변경: std::apply_result, std::is_applicable, std::is_nothrow_applicable |
예제
#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';
}
가능한 출력:
[25, Hello, 9.31, c]
같이 보기
| 함수/템플릿 | 설명 |
|---|---|
make_tuple (C++11) |
인자 타입으로 결정된 타입의 튜플 객체를 생성해요 (함수 템플릿) |
forward_as_tuple (C++11) |
전달 참조의 튜플을 생성해요 (함수 템플릿) |
make_from_tuple (C++17) |
튜플 인자들로 객체를 생성해요 (함수 템플릿) |
invoke, invoke_r (C++17) (C++23) |
주어진 인자로 임의의 호출 가능한 객체를 호출하고, 반환 타입을 지정할 수 있어요 (C++23부터) (함수 템플릿) |
is_applicable, is_nothrow_applicable (C++26) (C++26) |
주어진 튜플 인자들로 (마치 std::invoke처럼) 타입을 호출할 수 있는지 확인해요 (클래스 템플릿) |
is_applicable_type, is_nothrow_applicable_type (C++26) (C++26) |
반영된 타입을 주어진 반영된 튜플 인자들로 (마치 std::invoke처럼) 호출할 수 있는지 확인해요 (함수) |
apply_result (C++26) |
주어진 튜플 인자들로 호출 가능한 객체를 호출한 결과 타입을 추론해요 (클래스 템플릿) |
apply_result (C++26) |
주어진 반영된 튜플 인자들로 호출 가능한 객체를 호출한 결과 타입을 추론해요 (함수) |