마이너한 기능들은 뺍니다.



C++23 언어 관련 주요 기능


1. if consteval

- if constexpr의 consteval 버전이 생깁니다.


2. Deducing this

- 이제 클래스에서 똑같은 함수를 non-const, const 버전으로 두 가지를 만드느라 생기는 중복코드가 대폭 간결해집니다.


3. auto(x), auto{x}

- 함수 파라미터에서 rvalue (정확히는 prvalue)로 카피해 전달해주는 기능입니다.


예제) 벡터에서 첫 원소와 똑같은 원소를 다 지우고 싶을때

auto elem = v.front();

std::erase(v.begin(), v.end(), elem);


이 때 auto elem = v.front();에서 무조건 복사가 생깁니다. C++23부터는

std::erase(v.begin(), v.end(), auto(v.front());

로 복사를 막을 수 있습니다.


4. #elifdef, #elifndef, #warning

- 전처리 지시문입니다. 이름 보시면 뭐 하는건지 다 아실 테니 패스


5. operator[]의 다차원 버전 지원

- 이제 N차원 행렬 같은거 짤 때 arr[1, 3, 2, 4]같은 게 가능해집니다.


6. static operator()

이제 함수 오브젝트의 operator()도 static 멤버 함수로 쓸 수 있습니다.


7. [[assume]]

- Contract가 c++20에 들어가려다가 엎어지고, 그걸 함수의 사전조건과 사후조건을 다른 방식으로 표준에 편입시키는 것으로 합의되었는데,

이 중 함수의 사전조건을 컴파일러에게 알려주는 attribute입니다.




C++23 표준 라이브러리 관련 주요 기능


1. 리플렉션

- 드디어 C++에도 스택 트레이스가 생깁니다.


2. std::spanstream

- 본래 C++의 raw char array 버퍼 관련 입출력 스트림은 std::strstream이었습니다.

이건 90년대 초반에 나온 물건인데, 당시는 RAII 개념도 없었고

std::strstream이 쓰는 char* 버퍼의 메모리 소유권 관리가 매우 해괴한 방식이었기문에

std::string이 제대로 보급되고 나서 std::string 기반 std::stringstream을 대신 쓸 것이 권유되고

std::strstream은 무려 24년 전인 C++98에 deprecate 되었습니다.


"deprecate 된게 24년 전인데 왜 아직까지 remove 되지 않았느냐?"

std::string 기반 스트림과 char* 기반 스트림은 동작 방식이 많이 다르고,

char* 기반 스트림이 아무래도 성능 상으로 더 빠를 수밖에 없기 때문에

std::stringstream이 std::strstream을 완전히 대체할 수는 없었습니다.

"아예 없애지는 말아달라. 나는 필요할 때는 잘 쓴다." 라는 사람들이 있지요.


하지만 이제 C++20에 std::span이 추가 되면서 std::span<charT>를

스트림 버퍼로 쓸 수 있게 되었습니다. 이것이 std::spanstream입니다.

std::strstream은 C++26에서 완전히 삭제되어 deprecate 이후 28년만에 마침내 무덤으로 갈 가능성이 높습니다.



3. range 관련 대폭 개선

C++20의 range는 지원되는 기능이 많이 부실한 반쪽짜리였습니다.

이쪽의 본좌인 파이썬과 비교하면, 뭔가 되는게 없다는 느낌이 많이 들죠.


C++23에서는 이를 대폭 개선해 기능상으로는 파이썬 range에 밀리지 않는 수준까지 보강했습니다.

(타이핑해야 하는 글자 수는.. 그건 말씀드리기 싫습니다.)


- ranges::starts_with, ranges::end_with / 파이썬 startswith(), endswith()는 string만 받는데 이건 range를 받습니다.


- ranges::contains / 이게 c++20에 없었다니..


- ranges::iota / 드디어 C++에서도 for i in range(30) 같은 문법이 가능해집니다.


- views::zip / 드디어 C++에도 zip()이 생깁니다.


- views::chunk, views::slide, views::stride

예제)

std::vector v = {1, 2, 3, 4, 5, 6, 7};

fmt::print("{} ", v | std::views::chunk(2)); // [[1, 2], [3, 4], [5, 6], [7]]

fmt::print("{} ", v | std::views::slide(2)); // [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]]

fmt::print("{} ", v | std::views::stride(2)); // [1, 3, 5, 7]


- views::repeat / repeat하는 view


- views::cartesian_product / itertools.product()와 같습니다.


- ranges::to / range의 정보를 어떤 컨테이너 같은 곳에다 저장해야 할 때 씁니다.

예제)

auto even = [](int i) { return 0 == i % 2; };

auto v = ranges::iota(30) | views::filter(even) | ranges::to<std::vector<int>>;

하면 0부터 29까지 숫자 중 짝수로 이루어진 std::vector를 한 줄로 만들 수 있습니다.


- views::as_rvalue | rvalue로 casting하는 view



4. 표준 라이브러리의 모듈화 지원

C++20 모듈은 지원하는 컴파일러도 MSVC밖에 없습니다. (근데 버그가 존나 많아서 못써먹을 수준입니다)

MSVC는 표준 라이브러리를 import std.core; 식으로 모듈화 했는데요.

이렇게 헤더들이 어떤 모듈에 들어가는지를 C++23에서는 표준화 합니다.


5. <expected>

예외 처리를 성능 때문에 못 쓰는 사람들은 에러 코드를 써야 합니다.

이를 expected<T, E> 식으로 만들어서, 함수가 성공적으로 수행되었으면 T에 리턴값이 담기고,

아니면 E에 에러 코드가 담기는 방식을 표준에 넣었습니다.


6. <flat_map>, <flat_set>

std::set, std::map보다 lookup은 훨씬 더 빠르고 삽입/삭제는 훨씬 더 느린 정렬 컨테이너입니다.

boost꺼 가져올 가능성이 높은데 boost::container::flat_set, flat_map 삽입 삭제는 거의 못써먹을 정도로 느린데 걱정이 되네요.


7. std::mdspan

다차원 span입니다. 다차원 행렬을 만들 때 가장 빡치는 건 submatrix 짜는 건데,

이를 위해 딱이라고 볼 수 있네요.


8. format output 관련 대폭 개선

C++20의 std::format은 뭔가 안 되는게 많아서 그를 대폭 개선한 std::print 등이 나옵니다.

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2286r8.html 에 자세한 예제와 제안자의 한탄이 나오네요.




짱개 폐렴이 잦아드니 C++ 커미티에서도 작업이 쭉쭉 진행되어 가네요.


C++11은 엄청난 혁신이었지만 뭔가 반쪽짜리로 내놓은게 많아서 C++14가 그것을 완성했습니다.


C++20도 엄청난 혁신이었지만 급하게 내놓느라 모듈, 레인지, 포맷, 코루틴 등등 별로 좋은 평을 받고 있지 못해서

(완성도가 높다는 평을 받는건 컨셉 뿐입니다) C++23이 그를 완성하게 될 것 같네요.