2 분 소요

사용자 정의 리터럴

C++11 부터는 operator""_식별자()를 이용하여 사용자가 리터럴을 직접 정의할 수 있습니다. 동일한 값을 여러 단위계로 표현할 때 유용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// mm 단위로 리턴
int operator ""_km(long double val) {return std::round(val * 1000. * 1000.);}
int operator ""_m(long double val) {return std::round(val * 1000.);}
int operator ""_cm(long double val) {return std::round(val * 10.);}
int operator ""_mm(long double val) {return std::round(val);}   
int operator ""_mm(unsigned long long val) {return val;}  // 정수형 리터럴도 오버로딩

EXPECT_TRUE(1.5_km == 1500.0_m);
EXPECT_TRUE(1.5_m == 150.0_cm);
EXPECT_TRUE(1.5_cm == 15.0_mm);
EXPECT_TRUE(1.5_mm == 1.5_mm); // 반올림 하므로 2._mm와 동일합니다.

EXPECT_TRUE(1_km == 1000.0_m); // (X) 컴파일 오류. long double만 오버로딩 되었습니다.
EXPECT_TRUE(1_mm == 1); // mm는 정수형도 오버로딩 되었습니다.    

(C++14~) 표준 사용자 정의 리터럴이 추가되어 operator ""s, operator ""min, operator ""if, 등 문자열, 날짜 / 시간, 복소수 관련 표현이 간편해 졌습니다.

문자열 추론

기존 문자열을 auto로 초기화 하면 const char*로 추론되는데요, 사용자 정의 리터럴을 만들어 string으로 추론되게 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// const char* 형의 문자열을 std::string으로 변환
std::string operator ""_forced_string(const char* str, size_t size) {
    std::cout << "String Size : " << size << std::endl; // 전달된 문자열의 길이입니다.(널문자는 포함되지 않습니다.)
    return std::string(str);
}

auto chars_11 = "test"; // const char*
// EXPECT_TRUE(chars_11.size() == 4); // (X) 컴파일 오류. const char*이므로 size() 멤버 함수가 없습니다

auto str_11 = "test"_forced_string; // std::string
EXPECT_TRUE(str_11.size() == 4); // (O)

EXPECT_TRUE("hello"_forced_string.size() == 5); // 임시 개체도 가능합니다.

(C++14~) 표준 사용자 정의 리터럴이 추가되어 operator ""s, operator ""min, operator ""if, 등 문자열, 날짜 / 시간, 복소수 관련 표현이 간편해 졌습니다. 상기와 같은 경우 "test"s로 사용하면 됩니다.

식별자 규칙

식별자는 밑줄(_)로 시작해야 하며, 이중 밑줄은 허용하지 않습니다.

인자 규칙

사용할 수 있는 인자의 형태는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 정수 1_a
ReturnType operator ""_a(unsigned long long); 
// 실수 1.0_b
ReturnType operator ""_b(long double);              
// 문자 'a`_c
ReturnType operator ""_c(char);                    
ReturnType operator ""_d(wchar_t);                  
ReturnType operator ""_e(char16_t);                 
ReturnType operator ""_f(char32_t);                 
// 문자열 "abc"_g
ReturnType operator ""_g(const char*, size_t);      
ReturnType operator ""_h(const wchar_t*, size_t);   
ReturnType operator ""_i(const char16_t*, size_t); 
ReturnType operator ""_j(const char32_t*, size_t); 
// Raw : 3.14_k 처럼 정수나 실수 형태로 전달하고, 전달된 인자는 문자열 3.14로 전달됨
ReturnType operator ""_k(const char*);              
// template
template<char...> ReturnType operator ""_l();       

문자열과 Raw 타입이 모두 const char*를 사용해서 헷갈리는데요,

  • "3.14"_a와 같이 문자열 상수처럼 호출하면, int operator ""_a(const char* str, size_t size)이 호출되고,
  • 3.14_a와 같이 정수나 실수 형태로 사용하면 int operator ""_a(const char* str)가 호출됩니다.
1
2
3
4
5
6
7
8
9
int operator ""_a(const char* str, size_t size) {
    return 1;
}
int operator ""_a(const char* str) {
    return 2;
}

EXPECT_TRUE("3.14"_a == 1); // int operator ""_a(const char* str, size_t size) 버전이 호출됩니다.
EXPECT_TRUE(3.14_a == 2); // int operator ""_a(const char* str)  버전이 호출됩니다.

Raw 타입은 우선 순위가 낮습니다. 만약 const char*long double이 같은 식별자로 정의되었다면, long double이 사용됩니다. 따라서 Raw 타입은 다른 타입과 동일한 식별자를 사용하지 말아야 합니다.

1
2
3
4
5
6
7
int operator ""_a(const char* str) { // (△) 비권장. 우선 순위가 낮습니다. 다른 타입과 동일한 식별자를 사용하지 마세요.
    return 2;
}
int operator ""_a(long double val) { 
    return 3;
}
EXPECT_TRUE(3.14_a == 3); // int operator ""_a(long double val) 버전이 호출됩니다.

(C++20~) 사용자 정의 리터럴 인자 규칙 char8_t

인자 규칙char8_t가 추가되었습니다.

1
2
ReturnType operator ""_m(char8_t); 
ReturnType operator ""_n(const char8_t*, size_t); 

태그:

카테고리:

업데이트:

댓글남기기