C++26 미리 맛보기: 리플렉션부터 std::execution, <linalg>, <simd>, 컨트랙트까지

2025년 6월, 소피아 회의에서 C++26의 기능 동결(feature freeze) 이 완료되었습니다. 가장 큰 뉴스는 말 그대로 “게임 체인저”인 컴파일 타임 리플렉션의 채택. 이번 여름에 위원회 초안(CD) 투표로 나가고, 2026년 3월 두 번의 마무리 회의 이후 표준이 확정되는 로드맵입니다.

아래에서는 현시점에서 가장 실용적이고 손에 잡히는 변화들을 정리하고, 바로 돌려볼 수 있는 짧은 예제 코드를 곁들였습니다.


한눈에 보는 하이라이트

  • 리플렉션(compile-time reflection): P2996 등 7개 관련 문서가 C++26 초안에 채택. “새로운 언어”라고 불릴 만큼 영향력이 큽니다.
  • std::execution(Senders/Receivers): 비동기 작업 그래프의 표준 모델. just, then, when_all, sync_wait 등으로 구성합니다.
  • 표준 선형대수 <linalg>: BLAS 스타일 연산을 std::mdspan 기반으로 제공합니다.
  • 데이터 병렬 타입 <simd>: 휴대 가능한 SIMD 벡터 타입과 관련 알고리즘.
  • 컨트랙트(Contracts): pre(...), post(...), contract_assert(...) 로 사전·사후조건과 불변식을 기술. 2025년 2월 합의가 잡혔습니다.
  • 그 외: constexpr 예외(상수평가 중 예외 허용), std::hive, std::inplace_vector, 병렬 Range 알고리즘, std::text_encoding, hazard_pointer/rcu 등 다수.

1) 리플렉션: “코드가 스스로를 읽고, 생성한다”

C++26의 리플렉션은 하나의 불투명 타입 std::meta::info프로그램 요소의 메타데이터를 다루고, 접두 연산자 ^^리플렉션 값을 얻고, [: ... :] 스플라이스(splice) 로 코드 조각을 생성합니다. 여기에 컴파일 타임 반복을 위한 template for(Expansion statements) 까지 합류합니다.

아래는 구조체의 멤버 이름을 상수로 뽑아 런타임에 출력하는 개념 예시입니다(초기 구현/컴파일러별 문법 차이가 있을 수 있습니다).

// (C++26 개념 예시) — P2996/P1306 기반 pseudo-ish 코드
import std;

struct Person { int id; std::string name; };

consteval auto member_names() {
  std::vector<std::string> names;
  // ^^T : 타입의 리플렉션, members_of : 멤버 시퀀스, name_of : 이름
  template for (auto m : std::meta::members_of(^^Person)) {
    names.push_back(std::meta::name_of(m));
  }
  return names; // 컴파일타임 생성 결과
}

int main() {
  for (auto&& n : member_names()) {
    std::println("member = {}", n);
  }
}

리플렉션 도입과 함께 컴파일타임 예외 허용(P3068)이 필요했고, 실제로 반영되었습니다.


2) std::execution: 표준 비동기 파이프라인

Senders/Receivers 모델이 <execution>으로 표준화되었습니다. 작은 빌딩 블록을 파이프(|)로 이어 작업 그래프를 선언적으로 구성하고, sync_wait로 동기화합니다.

#include <execution>
#include <print>
#include <thread>

using namespace std::execution;

int main() {
  auto work =
    just(21)
    | then([](int v) { return v * 2; })
    | then([](int v) { std::print("answer = {}\n", v); return v; });

  std::this_thread::sync_wait(std::move(work));
}

이 모델은 코루틴·스레드풀과 잘 엮이도록 async_scope, parallel scheduler 등이 함께 들어왔습니다.


3) <linalg>: mdspan 위에서 돌리는 BLAS 스타일 연산

<linalg>std::mdspan을 뷰로 사용합니다. 데이터 레이아웃과 크기 정보가 분리되므로 외부 라이브러리(예: GPU BLAS) 연동이나 메모리 접근 최적화가 쉬워집니다.

#include <linalg>
#include <mdspan>
#include <vector>

int main() {
  std::vector<double> A = {1,2,3,4}; // 2x2
  std::vector<double> x = {1,1};     // 2x1

  std::mdspan M(A.data(), 2, 2);
  std::mdspan v(x.data(), 2);

  std::array<double,2> ybuf{};
  std::mdspan y(ybuf.data(), 2);

  std::linalg::matrix_vector_product(M, v, y); // y = M * v
}

또한 일부 연산은 실행 정책과 결합하여 병렬로 돌릴 수 있습니다.

std::linalg::scale(std::execution::par_unseq, 3.0, y); // 요소별 3배

4) <simd>: 휴대 가능한 데이터 병렬 타입

<simd>std::datapar::simd<T, N>데이터 병렬 타입과 알고리즘을 제공합니다. 벡터 폭과 ABI는 구현이 결정하지만, 코드 자체는 이식성을 유지합니다.

#include <simd>
#include <array>

using std::datapar::simd;
using std::datapar::reduce;

int main() {
  simd<float, 8> a{1,2,3,4,5,6,7,8};
  simd<float, 8> b{1};
  auto c = a + b;          // 요소별 연산
  float s = reduce(c);     // 수평 합
}

5) 컨트랙트(Contracts): 사전·사후조건을 언어 차원에서

컨트랙트는 함수 선언에 pre(...), post(...)를, 본문 안에서는 contract_assert(...)를 씁니다. 위반 시 관찰/강제/빠른 강제 등 평가 모드가 구현에 의해 선택됩니다.

#include <contracts>

int divide(int a, int b)
  pre(b != 0)           // 사전조건: 0으로 나누지 않기
{
  return a / b;
}

void push_positive(std::vector<int>& v, int x) {
  contract_assert(x > 0);
  v.push_back(x);
}

컨트랙트는 2025년 2월 회의에서 C++26에 포함되는 형태로 정리되었습니다.


6) 작은 보석들(실무에서 바로 유용)

  • constexpr 예외: 상수평가 중 throw 를 허용. 리플렉션의 오류 모델에도 활용됩니다.
  • std::hive: 지워진 자리의 메모리를 재사용하는 블록형 컨테이너(안정적인 반복자).
  • std::inplace_vector: 고정 용량을 객체 내부에 들고 있는 vector 스타일 컨테이너. 힙 할당 없는 실시간 환경에 적합.
  • 병렬 Range 알고리즘·코루틴 Task 타입 등 비동기/병렬 보완.
  • std::text_encoding: 실행 환경의 문자 인코딩 식별.
  • hazard_pointer, rcu: 메모리 회수 기법의 표준화(락-프리 구조에서 유용).

7) 바로 써 보려면: 플래그, 피쳐 테스트, 현재 지원

  • 컴파일러는 보통 GCC/Clang: -std=c++2c, MSVC는 **/std:c++latest**로 최신 기능이 켜집니다(세부 제공 기능은 각 버전에 따라 다름). GCC·Clang은 이미 C++26 언어 기능의 상당 부분을 구현했다는 위원장 리포트가 있습니다.
  • 조건부 사용을 위해 <version>피처 테스트 매크로를 추천합니다.
#include <version>
#if defined(__cpp_lib_linalg) && __cpp_lib_linalg >= 202311L
  // C++26 <linalg> 사용 코드
#endif
#if defined(__cpp_contracts)
  // 컨트랙트 사용 코드
#endif

8) 팀에 도입하는 작은 순서

  1. 알고리즘 핫스팟<simd> 또는 <linalg>로 가벼운 승리부터.
  2. 비동기 파이프라인 통일 → 신규 코드부터 std::execution 채택, 래핑 유틸 제작.
  3. 컨트랙트는 “문서화 + 방어”의 대체: 테스트와 리딩 가독성이 같이 좋아집니다.
  4. 리플렉션은 라이브러리 레벨에서: 직렬화/바인딩/검증 코드의 보일러플레이트 제거.

커뮤니티에서도 C++26 변화는 활발히 논의 중입니다(예: 뉴스·토론 스레드).


마무리

C++26은 “점진적 업데이트”가 아니라 언어 사용 패턴 자체를 바꾸는 릴리스가 될 가능성이 큽니다. 리플렉션으로 라이브러리를, std::execution으로 비동기를, <simd>/<linalg>로 수치 코드를, 컨트랙트로 안전성을 표준 C++ 만으로 끌어올릴 수 있게 되었죠. 이제는 작게 도입해 보면서 팀의 코딩 규약과 빌드 설정을 C++26 시대에 맞춰 정리할 때입니다.

주의: 본 글의 코드는 C++26 스펙에 맞춘 예시입니다. 일부 컴파일러/표준 라이브러리는 아직 구현이 진행 중이므로 동작·헤더·네임스페이스가 약간씩 다를 수 있습니다(각 항목의 원문/레퍼런스를 확인하세요).

반응형