Fold expressions (since C++17)
From cppreference.net
( fold 를 통해) pack 을 이항 연산자로 축소합니다.
목차 |
구문
(
pack op
... )
|
(1) | ||||||||
( ...
op pack
)
|
(2) | ||||||||
(
pack op
...
op init
)
|
(3) | ||||||||
(
init op
...
op pack
)
|
(4) | ||||||||
1)
단항 우측 폴드.
2)
단항 좌측 폴드.
3)
이진 오른쪽 폴드.
4)
이진 왼쪽 폴드.
| op | - | 다음 32개의 이항 연산자 중 하나: + - * / % ^ & | = < > << >> + = - = * = / = % = ^ = & = | = <<= >>= == ! = <= >= && || , . * - > * . 이항 fold에서 두 op 는 반드시 동일해야 합니다. |
| pack | - | 펼쳐지지 않은 pack 을 포함하고 최상위 레벨에서 cast보다 낮은 우선순위 를 가진 연산자를 포함하지 않는 표현식 (공식적으로는 cast-expression ) |
| init | - | 펼쳐지지 않은 pack 을 포함하지 않고 최상위 레벨에서 cast보다 낮은 우선순위 를 가진 연산자를 포함하지 않는 표현식 (공식적으로는 cast-expression ) |
폴드 표현식의 여는 괄호와 닫는 괄호는 필수적인 부분입니다.
설명
fold expression 의 인스턴스화는 다음처럼 표현식 e 을 확장합니다:
1)
단항 우측 폴드
(E
op
...)
는 다음이 됩니다
(E
1
op
(
...
op
(E
N-1
op
E
N
)))
2)
단항 좌측 폴드
(...
op
E)
는 다음과 같이 변환됩니다
(((E
1
op
E
2
)
op
...
)
op
E
N
)
3)
이항 오른쪽 폴드
(E
op
...
op
I)
는 다음이 됩니다
(E
1
op
(
...
op
(E
N−1
op
(E
N
op
I))))
4)
이항 왼쪽 폴드
(I
op
...
op
E)
는 다음과 같이 변환됩니다
((((I
op
E
1
)
op
E
2
)
op
...
)
op
E
N
)
(여기서
N
은 팩 확장의 요소 개수임)
예를 들어,
template<typename... Args> bool all(Args... args) { return (... && args); } bool b = all(true, true, true, false); // all() 함수 내에서 단항 좌측 폴드는 다음과 같이 확장됩니다 // return ((true && true) && true) && false; // b는 false입니다
단항 폴드가 길이가 0인 팩 확장과 함께 사용될 때, 다음 연산자들만 허용됩니다:
1)
논리 AND (
&&
). 빈 패킷의 값은
true
입니다.
2)
논리적 OR (
||
). 빈 패킷의 값은
false
입니다.
3)
콤마 연산자 (
,
). 빈 팩에 대한 값은
void
(
)
입니다.
참고 사항
init 또는 pack 으로 사용되는 표현식의 최상위 수준에서 우선순위 가 캐스트보다 낮은 연산자를 포함하는 경우, 반드시 괄호로 묶어야 합니다:
template<typename... Args> int sum(Args&&... args) { // return (args + ... + 1 * 2); // 오류: 캐스트보다 우선순위가 낮은 연산자 return (args + ... + (1 * 2)); // 정상 }
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_fold_expressions
|
201603L
|
(C++17) | Fold expressions |
예제
이 코드 실행
#include <climits> #include <concepts> #include <cstdint> #include <iostream> #include <limits> #include <type_traits> #include <utility> #include <vector> // 기본 사용법, operator<<에 대한 가변 인자 폴딩 template<typename... Args> void printer(Args&&... args) { (std::cout << ... << args) << '\n'; } // 패킷을 직접 사용하는 표현식을 operator,에 대해 폴딩 template<typename... Ts> void print_limits() { ((std::cout << +std::numeric_limits<Ts>::max() << ' '), ...) << '\n'; } // 패킷을 사용한 operator&&에 대한 폴딩과 // 가변 인자를 사용한 operator,에 대한 폴딩 모두 template<typename T, typename... Args> void push_back_vec(std::vector<T>& v, Args&&... args) { static_assert((std::is_constructible_v<T, Args&&> && ...)); (v.push_back(std::forward<Args>(args)), ...); } // 정수 시퀀스를 사용하여 람다를 operator,에 대해 폴딩하여 // 표현식을 N번 실행 template<class T, std::size_t... dummy_pack> constexpr T bswap_impl(T i, std::index_sequence<dummy_pack...>) { T low_byte_mask = static_cast<unsigned char>(-1); T ret{}; ([&] { (void)dummy_pack; ret <<= CHAR_BIT; ret |= i & low_byte_mask; i >>= CHAR_BIT; }(), ...); return ret; } constexpr auto bswap(std::unsigned_integral auto i) { return bswap_impl(i, std::make_index_sequence<sizeof(i)>{}); } int main() { printer(1, 2, 3, "abc"); print_limits<uint8_t, uint16_t, uint32_t>(); std::vector<int> v; push_back_vec(v, 6, 2, 45, 12); push_back_vec(v, 1, 2, 9); for (int i : v) std::cout << i << ' '; std::cout << '\n'; static_assert(bswap<std::uint16_t>(0x1234u) == 0x3412u); static_assert(bswap<std::uint64_t>(0x0123456789abcdefull) == 0xefcdab8967452301ULL); }
출력:
123abc 255 65535 4294967295 6 2 45 12 1 2 9
참조문헌
- C++23 표준 (ISO/IEC 14882:2024):
-
- 7.5.6 Fold 표현식 [expr.prim.fold]
- C++20 표준(ISO/IEC 14882:2020):
-
- 7.5.6 Fold expressions [expr.prim.fold]
- C++17 표준 (ISO/IEC 14882:2017):
-
- 8.1.6 Fold expressions [expr.prim.fold]
결함 보고서
다음 동작 변경 결함 보고서는 이전에 게시된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 2611 | C++17 | 폴드 표현식의 확장 결과가 괄호로 둘러싸이지 않았음 | 괄호로 둘러싸임 |