icon안동민 개발노트

C++ 20 기능 소개


개념 (Concepts)

 C++ 20은 C++ 11 이후 가장 큰 변화를 가져온 표준으로 평가받고 있습니다. 이 절에서는 C++ 20의 주요 기능들과 C++23에서 예정된 일부 기능들을 살펴보겠습니다.

 개념은 템플릿 인자에 대한 제약 조건을 명시적으로 정의할 수 있게 해주는 기능입니다.

기본 문법
template<typename T>
concept ConceptName = constraint-expression;
예제
#include <concepts>
#include <iostream>
 
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
 
template<Numeric T>
T add(T a, T b) {
    return a + b;
}
 
int main() {
    std::cout << add(5, 3) << std::endl;     // OK
    std::cout << add(3.14, 2.5) << std::endl; // OK
    // std::cout << add("Hello", "World") << std::endl; // 컴파일 에러
    return 0;
}

 개념을 사용하면 템플릿 코드의 가독성이 향상되고, 컴파일 오류 메시지가 더 명확해집니다.

범위-for 루프와 초기화 구문

 C++ 20에서는 범위-for 루프에 초기화 구문을 추가할 수 있게 되었습니다.

예제
#include <iostream>
#include <vector>
 
int main() {
    for (std::vector<int> v = {1, 2, 3, 4, 5}; const auto& elem : v) {
        std::cout << elem << ' ';
    }
    std::cout << std::endl;
    return 0;
}

모듈 (Modules)

 모듈은 헤더 파일의 한계를 극복하고 컴파일 속도를 개선하기 위해 도입되었습니다.

예제
// math.cpp
export module math;
 
export int add(int a, int b) {
    return a + b;
}
 
// main.cpp
import math;
#include <iostream>
 
int main() {
    std::cout << add(5, 3) << std::endl;
    return 0;
}

 모듈을 사용하면 헤더 파일의 중복 포함 문제를 해결하고, 컴파일 시간을 단축할 수 있습니다.

코루틴 (Coroutines)

 코루틴은 함수의 실행을 중단하고 재개할 수 있는 기능을 제공합니다.

예제
#include <iostream>
#include <coroutine>
 
struct Generator {
    struct promise_type {
        int current_value;
        Generator get_return_object() { return Generator{this}; }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
        std::suspend_always yield_value(int value) {
            current_value = value;
            return {};
        }
    };
 
    Generator(promise_type* p) : coro(std::coroutine_handle<promise_type>::from_promise(*p)) {}
    ~Generator() { if (coro) coro.destroy(); }
 
    int get_next() {
        coro.resume();
        return coro.promise().current_value;
    }
 
private:
    std::coroutine_handle<promise_type> coro;
};
 
Generator count_to(int n) {
    for (int i = 1; i <= n; ++i) {
        co_yield i;
    }
}
 
int main() {
    auto generator = count_to(5);
    for (int i = 0; i < 5; ++i) {
        std::cout << generator.get_next() << ' ';
    }
    std::cout << std::endl;
    return 0;
}

삼중 비교 연산자 <=>

 삼중 비교 연산자는 두 객체의 순서 관계를 한 번에 결정할 수 있게 해줍니다.

예제
#include <iostream>
#include <compare>
 
struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;
};
 
int main() {
    Point p1{1, 2}, p2{1, 3};
    if (p1 < p2) {
        std::cout << "p1 is less than p2" << std::endl;
    } else if (p1 > p2) {
        std::cout << "p1 is greater than p2" << std::endl;
    } else {
        std::cout << "p1 is equal to p2" << std::endl;
    }
    return 0;
}

constexpr 기능 확장

 C++ 20에서는 constexpr의 기능이 크게 확장되어, 더 많은 코드를 컴파일 타임에 실행할 수 있게 되었습니다.

예제
#include <vector>
#include <iostream>
 
constexpr std::vector<int> get_fibonacci(int n) {
    std::vector<int> fib(n);
    fib[0] = 0;
    fib[1] = 1;
    for (int i = 2; i < n; ++i) {
        fib[i] = fib[i-1] + fib[i-2];
    }
    return fib;
}
 
int main() {
    constexpr auto fib = get_fibonacci(10);
    for (auto n : fib) {
        std::cout << n << ' ';
    }
    std::cout << std::endl;
    return 0;
}

C++ 23 예정 기능: std::expected

 C++ 23에서는 오류 처리를 위한 std::expected 클래스가 추가될 예정입니다.

예제
#include <expected>
#include <iostream>
#include <string>
 
std::expected<int, std::string> safe_divide(int a, int b) {
    if (b == 0) {
        return std::unexpected("Division by zero");
    }
    return a / b;
}
 
int main() {
    auto result = safe_divide(10, 2);
    if (result) {
        std::cout << "Result: " << *result << std::endl;
    } else {
        std::cout << "Error: " << result.error() << std::endl;
    }
 
    result = safe_divide(10, 0);
    if (result) {
        std::cout << "Result: " << *result << std::endl;
    } else {
        std::cout << "Error: " << result.error() << std::endl;
    }
 
    return 0;
}

연습 문제

  1. Sortable 개념을 정의하고, 이를 사용하여 제네릭 버블 정렬 함수를 구현하세요. int, double, 그리고 사용자 정의 클래스에 대해 테스트하세요.
  2. 코루틴을 사용하여 피보나치 수열을 생성하는 제너레이터를 구현하세요.


참고 자료

  • C++20 표준 문서
  • "C++20 : The Complete Guide" by Nicolai M. Josuttis
  • CppCon 발표 영상들 - C++20 관련 세션들
  • C++ Reference 웹사이트의 C++20 섹션
  • C++ Core Guidelines