C++ 최신 문법 총정리: C++11부터 C++23까지
C++11/14의 주요 기능
auto 키워드
auto 키워드는 컴파일러가 초기화 표현식으로부터 변수의 타입을 자동으로 추론할 수 있게 해준다.
auto x = "Chris"; // 올바름
auto x; // 에러 - 반드시 초기화 필요
// 포인터와 참조 사용
auto myCatPtr = myCat; // 포인터
auto& myCatRef = myCat; // 참조
const auto& value = getValue(); // const 참조
auto는 복잡한 타입을 간단하게 표현할 수 있어 특히 반복자나 템플릿 매개변수에 유용하다.
그러나 가독성을 위해 다음과 같이 주의해야 될 점이 있다.
- auto보다 실제 자료형 사용을 권장
- 템플릿 매개변수와 반복자에는 auto 사용
- auto보다 auto*를 사용 (포인터일 경우)
- auto&보다 const auto&를 사용 (참조일 경우)
nullptr
기존의 NULL 대신 도입된 nullptr은 포인터 타입에 특화된 null 값
Class* myClass = new Class("COMP3200");
const Student* student = myClass->GetStudent("Coco");
if (student != nullptr) {
std::cout << student->GetID() << ":" << student->GetName() << std::endl;
}
nullptr은 정수 타입과의 모호함을 제거하여 함수 오버로딩 시 발생할 수 있는 문제를 해결
고정폭 정수형
크기가 명확한 정수 타입을 제공
int8_t / uint8_t // 1바이트
int16_t / uint16_t // 2바이트
int32_t / uint32_t // 4바이트
int64_t / uint64_t // 8바이트
범위 기반 for 문
배열이나 컨테이너를 순회할 때 더 간결한 문법을 제공
string companies[] = {"Apple", "Tesla", "Google", "Nvidia"};
// 기존 방식
for (int i = 0; i < sizeof(companies) / sizeof(string); i++) {
cout << companies[i] << "\n";
}
// 범위 기반 for 문
for (string company : companies) {
cout << company << "\n";
}
람다 표현식
익명 함수를 생성할 수 있는 람다 표현식을 도입
auto sum = [](int a, int b) { return a + b; };
std::cout << sum(3, 4); // 출력: 7
// 캡처 사용
int multiplier = 5;
auto multiply = [multiplier](int value) { return value * multiplier; };
std::cout << multiply(10); // 출력: 50
람다는 코드의 간결성과 가독성을 높이며, 알고리즘 함수에 콜백으로 전달하기에 편리
enum class
기존 enum의 문제점을 해결한 강력한 열거형
enum class Color : uint8_t {
Black,
White,
Red,
// Final = 0x100 // 경고! uint8_t 범위 초과
};
Color c = Color::Black; // 반드시 스코프 지정 필요
enum class는 형 안전성을 제공하고, 이름 충돌 문제를 해결
STL 확장
정렬되지 않은 컨테이너와 같은 새로운 STL 컨테이너가 추가
// unordered_map: 해시 테이블 기반 맵
std::unordered_map<std::string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
// array: 고정 크기 배열의 STL 래퍼
std::array<int, 5> numbers = {1, 2, 3, 4, 5};
unordered_map은 탐색 시 O(1)의 성능을 제공하여 자주 조회가 필요한 경우 유용
C++17의 주요 기능
if-init 문
조건문 내부에서 변수 초기화
if (auto it = map.find(key); it != map.end()) {
// it은 if 블록 내에서만 유효
std::cout << it->second << std::endl;
} else {
// it은 여기서도 유효
std::cout << "Key not found" << std::endl;
}
C++20의 주요 기능
우주선 연산자(Spaceship Operator)
비교 연산을 단순화하는 새로운 연산자 <=>가 도입
#include <compare>
struct MyType {
int value;
auto operator<=>(const MyType& other) const = default;
};
int main() {
MyType a{5};
MyType b{10};
auto result = a <=> b;
if (result < 0)
std::cout << "a is less than b\n";
else if (result == 0)
std::cout << "a is equal to b\n";
else
std::cout << "a is greater than b\n";
return 0;
}
여러 비교 연산자(<, <=, >, >=, ==, !=)를 한 번에 정의할 수 있어 코드가 크게 간소화
컨셉(Concepts)
템플릿 매개변수에 제약 조건을 지정
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// 사용
auto result1 = add(5, 3); // 정상
// auto result2 = add("a", "b"); // 컴파일 오류
템플릿 오류 메시지를 개선하고, 제약 조건을 명확하게 표현
코루틴(Coroutines)
함수 실행을 중간에 중단했다가 나중에 이어서 실행할 수 있는 코루틴
#include <coroutine>
#include <iostream>
struct Generator {
struct promise_type {
int value;
Generator get_return_object() { return Generator{this}; }
std::suspend_always initial_suspend() { return {}; }
std::suspend_always yield_value(int v) {
value = v;
return {};
}
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
// 코루틴 구현 생략...
};
Generator range(int start, int end) {
for (int i = start; i < end; i++) {
co_yield i;
}
}
코루틴은 비동기 프로그래밍, 이터레이터, 생성기 등 다양한 패턴을 구현하는 데 유용
모듈(Modules)
헤더 파일 대신 모듈을 사용하여 코드를 구성
// math.cppm
export module math;
export int add(int a, int b) {
return a + b;
}
// main.cpp
import math;
int main() {
int result = add(5, 3);
return 0;
}
모듈은 컴파일 속도를 향상시키고, 헤더 파일의 여러 문제점을 해결
C++23의 주요 기능
std::print와 std::println
출력을 위한 새로운 함수
#include <print>
int main() {
int age = 30;
std::string name = "Alice";
std::print("{}의 나이는 {}세입니다.\n", name, age);
std::println("{}의 나이는 {}세입니다.", name, age); // 자동 개행
return 0;
}
기존의 std::cout이나 printf보다 타입 안전성이 높고, 간결한 문법을 제공
- 숫자 형식 지정 예시
int number = 255;
std::print("10진수: {}, 16진수: {:#x}\n", number, number);
// 출력: 10진수: 255, 16진수: 0xff
std::format과 유사한 형식 지정자를 사용하여 다양한 출력 형식을 지원
연역 this 포인터
멤버 함수의 this 포인터 타입을 명시적으로 지정
struct S {
void f(this S& self) {
// 'this'가 아닌 'self'로 접근
}
template<typename Self>
void g(this Self&& self) {
// 보편 참조(universal reference)로 this 사용
}
};