Namespaces
Variants

Fold expressions (since C++17)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

( 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 폴드 표현식의 확장 결과가 괄호로 둘러싸이지 않았음 괄호로 둘러싸임