#4. [모던 C++ STL] 유틸리티
- (C++11~) tuple이 추가되어 다수의 요소를 관리할 수 있는 데이터 전달용 개체를 좀 더 간편하게 만들 수 있습니다.
- (C++11~) move()가 추가되어 좌측값을 우측값으로 형변환할 수 있습니다.
- (C++11~) move_if_noexcept()가 추가되어 nothrow 보증이 되는 경우에만
&&
로 형변환할 수 있습니다.- (C++11~) forward()가 추가되어 함수가 전달받은 인자를 다른 함수로 완벽하게 전달할 수 있습니다.
- (C++11~) declval()이 추가되어 참조 타입 표현식으로 변경할 수 있습니다.
- (C++11~) quick_exit(), _Exit(), at_quick_exit()가 추가되었습니다.
- (C++11~) va_copy가 추가되었습니다.
- (C++14~) exchange()가 추가되어 주어진 값을 바꾸는 작업이 간편해 졌습니다. 특히 이동 생성자와 이동 대입 연산자 구현에 활용할 수 있습니다.
- (C++17~) as_const()가 추가되어 인자에 const를 좀더 간편하게 붙일 수 있습니다.
- (C++17~) optional이 추가되어 값이 있을 수도 있고, 없을 수도 있는 데이터를 처리할 수 있어, 미확정 상태, 값을 처리하기 부적절한 상태, 함수 리턴값 성공 여부 처리를 좀더 단순하게 할 수 있습니다.
- (C++17~) any가 추가되어 타입의 변동 가능성이 있는 데이터를 비교적 안전하게 사용할 수 있습니다.
- (C++17~) variant가 추가되어 타입이 다른 여러 데이터들을 동일한 메모리 공간에서 쉽게 관리할 수 있습니다.
- (C++17~) inplace등이 추가되었습니다. 내부 개체를 생성해서 전달하는 것이 아니라, 내부 개체의 생성자 인수들을 전달하면 내부 개체를 직접 생성하라는 의미로 optional, any, variant 생성자에 더미(Dummy) 개체로 사용됩니다.
- (C++17~) timespec_get(), timespec이 추가되었습니다.
- (C++20~) 삼중 비교 연산자가 추가되어 !=, >, <=, >=는 deprecate 되었습니다.
- (C++20~) cmp_equal(), cmp_not_equal(), cmp_less(), cmp_greater(), cmp_less_equal(), cmp_greater_equal()이 추가되어 음의 정수와 양의 정수를 정상적으로 비교할 수 있습니다.
- (C++20~) in_range()가 추가되었습니다. 주어진
value
가 주어진type
의 값 범위 내에 있는지 검사합니다.- (C++20~) source_location이 추가되어 파일명, 줄번호, 칼럼번호, 함수명등의 정보를 제공합니다.
- (C++20~) 삼중 비교 관련 유틸리티들이 추가되었습니다.
- (C++20~) 유틸리티의 constexpr 지원이 개선되어
swap()
함수도 constexpr 함수로 변경되었습니다.- (C++20~) STL 지원 테스트 매크로가 추가되어 C++11부터 추가된 STL 기능을 지원하는지 테스트 할 수 있습니다.
일반 유틸리티
항목 | 내용 | constexpr |
---|---|---|
swap() |
바꿔치기 합니다. | (C++20~) |
exchange() (C++14~) | 주어진 값을 바꾸고 이전값을 리턴합니다. 이동 생성자와 이동 대입 연산자 구현에 활용할 수 있습니다. | (C++20~) |
간단한 데이터 개체
항목 | 내용 | constexpr |
---|---|---|
pair | first 와 second 로 2개의 요소를 관리합니다. make_pair() 를 이용하여 pair를 쉽게 생성할 수 있습니다. |
생성자에 따라, (C++11~) (C++14~) (C++20~) |
tuple (C++11~) | 다수의 요소를 관리할 수 있는 데이터 전달용 개체를 손쉽게 만듭니다. | 생성자에 따라, (C++11~) (C++14~) (C++20~) (C++23~) |
optional (C++17~) | 값이 있을 수도 있고, 없을 수도 있는 데이터를 처리할 수 있어, 미확정 상태, 값을 처리하기 부적절한 상태, 함수 리턴값 성공 여부 처리를 좀더 단순하게 할 수 있습니다. | 생성자에 따라, (C++17~) (C++20~) |
any (C++17~) | 타입의 변동 가능성이 있는 데이터를 비교적 안전하게 사용할 수 있습니다. | 생성자에 따라, (C++17~) |
variant (C++17~) | 타입이 다른 여러 데이터들을 동일한 메모리 공간에서 쉽게 관리할 수 있습니다. | (C++17~) |
개체 비교
대소 비교의 논리 조건에 따라 다음의 연산자가 제공됩니다.
항목 | 내용 |
---|---|
!= (~C++20) |
== 을 활용하여 구현되어 있습니다. |
>, <=, >= (~C++20) |
< 을 활용하여 구현되어 있습니다. |
하지만, C++20 부터 삼중 비교 연산자가 추가되어 모두 deprecate 되었습니다.
기존에는 signed
와 unsigned
를 비교하면, signed
를 unsigned
로 암시적으로 형변환 하기 때문에, 음의 정수와 양의 정수를 정상적으로 비교하지 못했습니다.
1
2
3
int x{-1}; // 0xFFFF FFFF(4294967295)
unsigned int y{1};
EXPECT_TRUE(x < y); // (X) 런타임 오류. -1은 unsigned int로 형변환되어 4294967295입니다.
C++20 부터는 cmp_equal(), cmp_not_equal(), cmp_less(), cmp_greater(), cmp_less_equal(), cmp_greater_equal()이 추가되어 음의 정수와 양의 정수를 정상적으로 비교할 수 있습니다.
항목 | 내용 | constexpr |
---|---|---|
cmp_equal() (C++20~) cmp_not_equal() (C++20~) cmp_less() (C++20~) cmp_greater() (C++20~) cmp_less_equal() (C++20~) cmp_greater_equal() (C++20~) |
음의 정수와 양의 정수를 정상적으로 비교 합니다. | (C++20~) |
in_range<type>(value) (C++20~) |
주어진 value 가 주어진 type 의 값 범위 내에 있는지 검사합니다. |
(C++20~) |
다음은 cmp_less()를 이용하여 음의 정수와 양의 정수를 비교하는 예입니다.
1
2
3
int x{-1};
unsigned int y{1};
EXPECT_TRUE(std::cmp_less(x, y)); // (O) 음수와 양수를 정상적으로 비교합니다.
in_range()는 주어진 value
가 주어진 type
의 값 범위 내에 있는지 검사합니다.
1
2
static_assert(std::in_range<unsigned int>(-1) == false); // unsigned int 범위 바깥입니다.
static_assert(std::in_range<unsigned int>(1) == true); // unsigned int 범위 입니다.
(C++11~) 타입 변환
항목 | 내용 | constexpr |
---|---|---|
move() (C++11~) | 좌측값을 우측값으로 형변환 합니다. | (C++14~) |
move_if_noexcept() (C++11~) | nothrow 보증이 되는 경우에만 && 로 형변환 합니다. |
(C++14~) |
forward() (C++11~) | 함수가 전달받은 인자를 다른 함수로 완벽하게 전달합니다. | (C++14~) |
forward_like() (C++23) |
(작성중) | |
declval() (C++11~) | 주어진 타입을 참조 타입으로 변환하여, 참조 타입 표현식으로 변경해 줍니다. | |
as_const(T& param) (C++17~) |
인자 param 에 const를 붙여 const T& 로 변환합니다. |
(C++17~) |
to_underlying() (C++23~) |
(작성중) | (C++23~) |
프로그램 지원
항목 | 내용 |
---|---|
abort() | 프로그램을 비정상 종료 시킵니다. terminate() 참고 |
exit() |
프로그램을 정상 종료 시킵니다. |
quick_exit() (C++11~) |
(작성중) |
_Exit() (C++11~) |
(작성중) |
atexit() |
(작성중) |
at_quick_exit() (C++11~) |
(작성중) |
EXIT_SUCCESS EXIT_FALURE |
(작성중) |
system() |
(작성중) |
getenv() |
(작성중) |
signal() |
(작성중) |
raise() |
(작성중) |
sig_atomic_t |
(작성중) |
SIG_DFL SIG_IGN |
(작성중) |
SIG_ERR |
(작성중) |
SIGABRT SIGFPE SIGILL SIGINT SIGSEGV SIGTERM |
(작성중) |
setjmp() |
(작성중) |
longjmp() |
(작성중) |
jump_buf() |
(작성중) |
unreachable() (C++23~) |
도달할 수 없는 실행 지점을 마킹합니다. |
가변 인자
가변 인자를 처리하는 예는 가변 인자를 참고하시기 바랍니다.
항목 | 내용 |
---|---|
va_start() | 가변 인자 액세스 시작 매크로 함수 |
va_arg() | 가변 인자 추출 매크로 함수 |
va_end() | 가변 인자 사용 종료 매크로 함수 |
va_list | 가변 인자에 대한 typedef |
va_copy (C++11) |
(작성중) |
C스타일 시간 유틸리티
항목 | 내용 |
---|---|
difftime() |
(작성중) |
time() |
(작성중) |
clock() |
(작성중) |
asctime() |
(작성중) |
ctime() |
(작성중) |
strftime() |
(작성중) |
wcsftime() |
(작성중) |
gmtime() |
(작성중) |
localtime() |
(작성중) |
mktime() |
(작성중) |
CLOCKS_PER_SEC |
(작성중) |
tm |
(작성중) |
time_t |
(작성중) |
clock_t |
(작성중) |
timespec_get() (C++17~) |
timespec 개체를 구합니다. |
timespec (C++17~) |
초(tv_sec )와 나노초(tv_nsec )로 구분합니다. |
(C++17~) 모호성 해소
항목 | 내용 |
---|---|
in_place (C++17~)in_place_type (C++17~)in_place_index (C++17~)in_place_t (C++17~)in_place_index_t (C++17~) |
내부 개체를 생성해서 전달하는 것이 아니라, 내부 개체의 생성자 인수들을 전달하면 내부 개체를 직접 생성하라는 의미로 optional, any, variant 생성자에 전달되는 더미(Dummy) 개체 입니다. |
(C++20~) source_location
기존에는 __LINE__
과 __FILE__
를 이용하여 줄번호와 파일명을 사용했는데요(__LINE__
, __FILE__
참고),
1
2
// Line Number:118 Filename:C:\XXX\XXX.cpp
std::cout << "Line Number:" << __LINE__ << " Filename:" << __FILE__ << std::endl;
C++20 부터는 source_location이 추가되어 파일명, 줄번호, 칼럼번호, 함수명등의 정보를 제공합니다.
다음의 Log()
함수는 메시지와 source_location을 이용한 부가 정보를 출력합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
void Log(std::string message, const std::source_location& location = std::source_location::current()) {
// Message.
// source_location : F:\Data\language_test\test\Test_ModernCpp_Utility.cpp, virtual void TestModern_Utility_Test::TestBody()(41, 12)
std::cout
<< message << std::endl
<< "source_location : "
<< location.file_name() << ", " << location.function_name() // 파일명, 함수명
<< "(" << location.line() << ", " << location.column() << ")"// 줄번호, 칼럼번호
<< std::endl;
}
Log("Message.");
(C++20~) 삼중 비교
C++20 부터 추가된 삼중 비교 연산자를 지원하는 유틸리티입니다.
항목 | 내용 | constexpr |
---|---|---|
strong_ordering (C++20~) | == , != , < , > , <= , >= 의 비교 연산을 제공합니다. 여기서 == 은 상등 비교입니다. 즉 데이터들이 완전히 동일함을 의미합니다. |
|
weak_ordering (C++20~) | == , != , < , > , <= , >= 의 비교 연산을 제공합니다. 여기서 == 은 동등 비교를 합니다. 즉, 개념적으로 동일함을 의미합니다. 예를들어 대소문자 구분없이 비교 할때 A 와 a 는 아스키 코드값이 다르므로 상등하지 않지만, 개념적으로 동등합니다. |
|
partial_ordering (C++20~) | == , != , < , > , <= , >= 의 비교 연산을 제공합니다. 실수 타입과 같이 대소 비교는 가능한데, == 는 소수점 오차등으로 상등 비교를 신뢰하기 애매한 경우입니다. |
|
strong_order() (C++20~) |
삼중 비교 연산자로 비교 하고 strong_ordering를 리턴합니다. | (C++20~) |
weak_order() (C++20~) |
삼중 비교 연산자로 비교 하고 weak_ordering를 리턴합니다. | (C++20~) |
partial_order() (C++20~) |
삼중 비교 연산자로 비교 하고 partial_ordering를 리턴합니다. | (C++20~) |
is_eq(), is_neq() (C++20~)is_lt(), is_lteq(), is_gt(), is_gteq() (C++20~) |
삼중 비교 연산자로 비교합니다. | (C++20~) |
compare_three_way (C++20~) |
삼중 비교 연산자로 비교하는 함수자입니다. | |
compare_three_way_result (C++20~) |
주어진 타입의 삼중 비교 연산자 리턴 타입의 별칭입니다. strong_ordering, weak_ordering, partial_ordering 중 하나입니다. | |
common_comparison_category (C++20~) |
주어진 타입의 비교 카테고리를 리턴합니다. | |
compare_strong_order_fallback() (C++20~) |
삼중 비교 연산자가 없는 경우에도 삼중 비교를 합니다. | (C++20~) |
compare_weak_order_fallback() (C++20~) |
삼중 비교 연산자가 없는 경우에도 삼중 비교를 합니다. | (C++20~) |
compare_partial_order_fallback() (C++20~) |
삼중 비교 연산자가 없는 경우에도 삼중 비교를 합니다. | (C++20~) |
다음은 삼중 비교 관련 유틸리티들의 사용예입니다.
compare_three_way
, strong_order()
등은 삼중 비교 연산자가 없으면 사용할 수 없으며,
compare_strong_order_fallback()
, compare_weak_order_fallback()
, compare_partial_order_fallback()
은 삼중 비교 연산자가 없는 경우이더라도 삼중 비교를 가능하게 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class T {
private:
int m_Val;
public:
explicit T(int val) : m_Val(val) {}
bool operator ==(const T& other) const {return m_Val == other.m_Val;}
bool operator <(const T& other) const {return m_Val < other.m_Val;}
// 삼중 비교 연산자가 없습니다.
// std::strong_ordering operator<=>(const T& other) const {return m_Val <=> other.m_Val;}
};
// EXPECT_TRUE(T{1} <=> T{2} == 0); // (X) 컴파일 오류. 삼중 비교 연산자가 없습니다.
// EXPECT_TRUE(std::compare_three_way{}(T{1}, T{2}) < 0); // (X) 컴파일 오류. 삼중 비교 연산자가 없습니다.
// EXPECT_TRUE(std::strong_order(T{1}, T{2}) < 0); // (X) 컴파일 오류. 삼중 비교 연산자가 없습니다.
EXPECT_TRUE(std::compare_strong_order_fallback(T{1}, T{2}) < 0); // 삼중 비교 연산자가 없더라도, 삼중 비교를 할 수 있습니다.
(C++20~) 유틸리티의 constexpr 개선
유틸리티에서 점진적으로 constexpr 지원을 개선하고 있습니다.
특히 C++20 부터는 swap()
함수도 constexpr 함수로 변경되었습니다.
따라서 다음과 같이 swap()
을 constexpr 함수내에서 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
constexpr std::pair<int, int> ConstSwap(int&& a, int&& b) {
int resultA{std::move(a)};
int resultB{std::move(b)};
std::swap(resultA, resultB); // 컴파일 타임에 두 수를 바꿔치기 합니다.
return std::make_pair(resultA, resultB);
}
constexpr std::pair<int, int> result{ConstSwap(0, 1)};
static_assert(result.first == 1 && result.second == 0);
(C++20~) STL 지원 테스트
C++20 부터는 STL 지원 테스트 매크로가 추가되어 C++11부터 추가된 STL 기능을 지원하는지 테스트 할 수 있습니다.(언어 지원 테스트 참고)
테스트할 수 있는 항목은 https://en.cppreference.com/w/cpp/feature_test#Library_features를 참고하시기 바랍니다.
1
2
3
4
5
#if __cpp_lib_string_view
std::cout << "Support string_view" << std::endl; // string_view를 지원합니다.
#else
std::cout << "No string_view" << std::endl;
#endif
댓글남기기