c++에 리터럴 주요 6개 카테고리가 있습니다. : interger, character, floating-point, string, boolean, and pointer. C++11 부터는 당신은 이러한 카테고리에 기반하는 자신만의 리터럴을 정의 할 수 있다. 이것은 통상적인 관용어에 대한 구문적인 숏컷과 타입 안정성적을 증가 시키기 위한 것이다. 예를 들어 당신은 distance 클래스를 갖고 있다고 말해보자. 당신은 킬로미터와 또다른 마일에 대한 리터럴을 정의할 수 있을 것이다. 그리고 유저들에게 이러한 단위 대해 명확하게 하는 것을 권할 것이다. : auto d = 42.0_km 또는 auto d = 42.0_mi. 사용자 정의 리터럴에 대한 이점과 단점은 없습니다. 이것은 컴파일 타임 형식 추런이나 편의성을 우선적으로 합니다. 이러한 표준 라이브러리는 <chrono> 헤더에 std:;string, std::complex 그리고 시간과 기간 연산 대한 사용자 정의를 갖습니다.
Distance d = 36.0_mi + 42.0_km; // Custom UDL (see below)
std::string str = "hello"s + "World"s; // Standard Library <string> UDL
complex<double> num =
(2.0 + 3.01i) * (5.0 + 4.3i); // Standard Library <complex> UDL
auto duration = 15ms + 42h; // Standard Library <chrono> UDLs
사용자 정의 리터럴 연산 기호
당신은 아래 형식중의 하나로 네임스페이스 범위 에서 operatr""를 이용해서 사용자 정의 리터럴을 구현합니다.
ReturnType operator "" _a(unsigned long long int); // Literal operator for user-defined INTEGRAL literal
ReturnType operator "" _b(long double); // Literal operator for user-defined FLOATING literal
ReturnType operator "" _c(char); // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _d(wchar_t); // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _e(char16_t); // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _f(char32_t); // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _g(const char*, size_t); // Literal operator for user-defined STRING literal
ReturnType operator "" _h(const wchar_t*, size_t); // Literal operator for user-defined STRING literal
ReturnType operator "" _i(const char16_t*, size_t); // Literal operator for user-defined STRING literal
ReturnType operator "" _g(const char32_t*, size_t); // Literal operator for user-defined STRING literal
ReturnType operator "" _r(const char*); // Raw literal operator
template<char...> ReturnType operator "" _t(); // Literal operator template
이전 예제의 연산자 이름은 당신이 제공하는 이름에 대한 플레이스 홀더 입니다. 앞에 언더스코어는 필수 입니다.(표준 라이브러리만 언더스코어 없이 리터럴을 정의하는 것이 가능합니다) 리턴 타입은 당신이 리터럴에 의해 수해오디는 변환이나 다른 연산자를 사용자 정의하는 곳입니다. 또한 이러한 연산들은 constexpr로도 정의될 수 있습니다.
Cooked Literals
소스코드에서 사용자 정의든 아니든 101 or 54.7, "hello", true 와 같은 알파벳 문자들 시퀀스는 필수적이다. 컴파일러는 시퀀스를 integer, float const char* string 등으로 해석한다. 컴파일러 리터럴 값으로 할당한 타입과 상관없이 입력으로 받아드려진 모든 사용자 리터럴 값은 비공식적으로 cook 리터럴로 알려진다. except _r 와 _t 위의 모든 연산자는 cooked literals이다. 예를 들어 리터럴 42.0_kim는 연산자를 _km로 바인드 시킨다. 그것은 _b 시그니처와 유사하다. 그리고 리터럴 42_kim는 연산자를 _a 시그니처와 비슷하게 바인딩 한다.
다음 예제넌 사용자 정의 리터럴이 호출자에게 사용자들의 입력에 대해 명확하게 할 것을 권하는 방법을 보여준다. Distance를 생성하기 위해서 우리는 반드시 kilometers 또는 milds를 적절한 사용자 리터럴을 사용하여 명확히 지정해야 한다. 당신은 다른 방법으로 같은 결과를 얻을 수 있다. 하지만 사용자 정의 리터럴은 다른 대안들 보다 간단한다.
// UDL_Distance.cpp
#include <iostream>
#include <string>
struct Distance
{
private:
explicit Distance(long double val) : kilometers(val)
{}
friend Distance operator"" _km(long double val);
friend Distance operator"" _mi(long double val);
long double kilometers{ 0 };
public:
const static long double km_per_mile;
long double get_kilometers() { return kilometers; }
Distance operator+(Distance other)
{
return Distance(get_kilometers() + other.get_kilometers());
}
};
const long double Distance::km_per_mile = 1.609344L;
Distance operator"" _km(long double val)
{
return Distance(val);
}
Distance operator"" _mi(long double val)
{
return Distance(val * Distance::km_per_mile);
}
int main()
{
// Must have a decimal point to bind to the operator we defined!
Distance d{ 402.0_km }; // construct using kilometers
std::cout << "Kilometers in d: " << d.get_kilometers() << std::endl; // 402
Distance d2{ 402.0_mi }; // construct using miles
std::cout << "Kilometers in d2: " << d2.get_kilometers() << std::endl; //646.956
// add distances constructed with different units
Distance d3 = 36.0_mi + 42.0_km;
std::cout << "d3 value = " << d3.get_kilometers() << std::endl; // 99.9364
// Distance d4(90.0); // error constructor not accessible
std::string s;
std::getline(std::cin, s);
return 0;
}
리터럴 숫자는 반드시 10진수를 사용한다. 그렇지 않으면 숫자는 정수형과 연산자와 호환 불가능한 타입으로 해석될 수 있다. 플로팅 포인 입력에서 타입은 반드시 long double 이여야 한다. 그리고 정수 타입에서는 반드시 longlong 타입이여야 한다.
예시: 로우 리터럴의 한계
로투 리터럴 연산자와 리터럴 연산자 템플릿은 오직 중서나 플로팅 포인트 사용자 정의 리터럴에서만 작동한다. 다른 예시에서 볼수 있듯이
문자열 리터럴은 널이 제거된 문자열을 형성하는 문자들 시퀀스를 함께 표현한다. 문자들은 반드시 쌍따옴표 안에 있어야한다. 다음에 문자열 리터럴의 종류가 있다.
좁은 문자열 리터럴
좁은 무자열 리터럴은 접두사가 없고 쌍따옴표로 구본되고, 널이 제거 된 const char[n] 타입의 배열이다. 여기서 n은 바이트 배열의 길이다. 좁은 문자열 리터럴은 싸따옴표, 백슬래쉬, 또는 개행 문자를 제외한 어떤 그래픽 문자도 포함할 수 있다. 좁은 문자열 리터럴은 또한 아래 정리된 이스케이프 시퀀스와 바이트에 맞는 범용 문자 이름 또한 포함 할수도 있다.
A UTF-8로 인코딩된 문자열은 u8-접두사가 있고, 쌍따옴표로 구분되어 있고 const char[n] 타입의 배열이다. 여기서 n은 인코딩된 바이트 배열의 길이이다. u8 접두사가 있는 문자열 리터럴은 또한 쌍따옴표, 백슬래쉬, 개행문자를 제외하고 어떤 그래픽 문자도 가질 수 있다. u8 접두사가 붙은 문자열 리터럴은 또한 아래 정리된 이스케이프 시퀀스와 어떤 범용 문자 이름을 포함 할수도 있다.
// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";
넓은 문자열 리터럴
넓은 문자열 리터럴은 널이 없는 wchar_t배열이고 wchar_t는 L 접두사가 붙는다. 그리고 쌍따옴표, 백슬래쉬 또는 개행문자를 제외한 어떤 그래픽 문자든지 포함한다. 넓은 문자열 리터럴은 아래 정리된 이스케이프 문자 시퀀스들과 아무 범용 캐릭터 이름을 포함할 수도 있다.
C++11 은 편한 char16_6(16비트 유니코드)와 char32_t(23비트 유니코드) 문자 타입들을 소개한다.
auto s3 = u"hello"; // const char16_t*
auto s4 = U"hello"; // const char32_t*
raw 문자열 리터럴(C++11)
raw문자열 리터럴은 널이 제거된 아무 문자 타입의 배열이다. 그리고 쌍따옴표, 백슬래쉬 또는 개행문자를 포함하고 아무 그래픽 문자를 포함한다. 로우 문자열 리터럴은 캐릭터 클래스를 사용하는 정규식과 html 문자열, xml 문자열에 사용된다. 샘플에 대한건 다음 기사를 확인 하세요.Bjarne stroustrup's FAQ on C++ 11
구분자는 최대 16문자로 구성된 사용자 정의 시퀀스입니다. 구분자는 로우 스트릴 문자열의 열린 괄호 앞에 있고 그리고 닫힌 과로 뒤에 있습니다. 예를 들어 rR"abc(Hello"\()abc"에서 구분자 시퀀스 이고 문자열 내용은 Hello"\C 입니다. 당신은 당신은 로우 문자열을 명확하게 구분하는 구분자를 사용할수 있습니다. 로우 문자열은 쌍따옴표마크나 광호를 모두 포함합니다. 이런 문자열은 컴파일 에러를 일으킵니다.
// meant to represent the string: )"
const char* bad_parens = R"()")"; // error C2059
그러나 구분자는 이것을 해결합니다.
const char* good_parens = R"xyz()")xyz";
당신은 개행(이스케이프 문자가 아닌)을 포함하는 로우 문자열 리터럴을 구성할 수 있습니다.
std::string 리터럴은 "xyz"s(접미사 s)처럼 표현되는 사용장 정의 리터럴의 표준 라이브러리 구현들이다. 문자열 리터럴 종류는 std::string, std::wstring, std::u32string, 또는 std::u16string과 같은 임시 객체를 생성한다. 이들은 지정된 접두사에 의존적이다. 접두사 없이 사용될 때는 위처럼 std::string이 생성된다. L"xyz"s는 std::wstring을 생성한다. u"xyz"s는 std::u16string를 생성하고 U"xyz"는 std::u32string을 생성한다.
std::string 문자열은 <string> 헤더 파일 안에 std::literals::string_literals 네임스페이스 안에 정의되어 있다. std::literals:;string_literals와 std::literals 모두 인라인 네임스페이스로 선언되어 있기 때문에 std::literals::string_literals는 자동으로 std 네임스페이스에 직접 소유되는 것 처럼 취급됩니다.
문자열 리터럴의 사이즈
ANSI char* 문자열과 기타 단독 바이트 인코딩인 경우, 문자열 리터럴의 크기는 제거 널 문자에서 문자 숫자를 1더한 것이다. 모든 다른 문자열 타입의 경우 크기가 엄격히 문자 갯수와 관련되어 있지는 않다. UTF-8은 일부 코드 유닛을 인코드하기 위해서 char를 4개까지 사용한다. utf-16으로 인코드 된 그리고 char16_t나 wchar_t는 단독 코드 유닛을 인코드 하기 위해서 2개의 요소(총 4바이트)를 사용한다. 이 예제는 넓은 문자열 리터럴의 바이트 사이즈를 보여준다.
strlen()과 scslen()은 종료 널 문자 사이즈를 포함하지 않고 사이즈는 문자열 타입의 요소 사이즈와 동일하다 : char* or char8_t* 문자열은 1바이트, wchar_t* 또는 char16_t* 문자열은 2바이트, char32_t* 문자열은 4바이트.
문자열 리터럴으 최대 길이는 65535 바이트이다. 이 최대치는 좁은 문자열 리터럴과 넓은 문자열 리터럴에 모두 적용된다.
문자열 리터럴 수정
문자열 리터럴(std:;string을 포함하지 않는)는 상수이기 때문에 그것들을 수정하는 것은(예시_str[2] = 'a') 컴파일 에러를 발생 시킨다.
마이크로소프트 관련
C++ 마이크로소프트에서 당신으 non-const char 또는 wchar_t 포인터를 초기화기 위해 사용할 수 있습니다. 이 non-const 초기화는 c99 에서 가능합니다. 하지만 이건 c++98에서 deprecate 됐고, C++11에서 제거 됐습니다. 문자열을 수정하는 시도는 예시처럼 접근 위반을 일으킵니다.
당신은 컴파일 옵션을 /Zc:strictStrings(Disable string literal type conversion)을 설정하고 non-const 문자 포인터로 문자열 리터럴을 번경하려고 하면 콤파일은 에러를 발생합니다. 우리는 표준을 따르는 포터블 코드를 따르는 방법을 추천합니다. 이것은 문자열 리터럴 초기화 포인터를 선언하기 위한 auto 키워드를 사용하는 좋은 연습입니다. 왜냐하면 이것은 정확한 타입으로 해결합니다. 예를 들어 아래 코드 샘플은 컴파일 타임에 문자열 리터럴을 쓰는 시도를 잡아 냅니다.
auto str = L"hello";
str[2] = L'a'; // C3892: you cannot assign to a variable that is const.
어떤 경우에는 실행파일에서 공간을 절약하기 위해 동일한 문자열 리터럴은 풀링된다. 문자열 리터럴 풀링에서 컴파일러는 특정 문자열 리터럴의 모든 참조가 메모리 상의 같은 위치를 가리키게 합니다. 문자열 리터럴에 개별의 인스턴스에 대한 각각의 참조를 갖는 대신에. 문자열 풀링을 하기 위해 컴파일러 옵션 /GF를 사용해라.
마이크로소프트 관련 섹션은 여기서 끝.
인접한 문자열 리터럴의 연결
인접한 넓은 또는 좁은 문자열 리터럴은 연결된다. 여기 선언은:
char str[] = "12" "34";
다음 선언과 동일하다.
char atr[] = "1234";
그리고 이 선언과도 동일하다.
char atr[] = "12\
34";
문자열 리터럴을 지정하기 위해 내장 16진수 이스케이프 코드를 쓰는 것은 예기치 못한 결과를 일으킨다. 다음 예제는 ascii 5 문자를 초함하는 문자열 리터럴을 만들려고 한다. 그 다음 f,i,v 그리고 e를 만듭니다.
"\x05five"
실제 결과는 아스키 코드 언더스코어 16진수 5f 그리고 i, v, e 이다. 정확한 결과를 얻기 위해서는 당신은 이러한 이스케이프 시퀀스중 하나를 사용할 수 있다.
"\005five" // Use octal literal.
"\x05" "five" // Use string splicing.
std::string 리터럴(std::ustring, std::u16string, ste:;u32string과 관련된) 은 basic_string 타입으로 지정된 + 연산자를 통해 연결된다. 그들은 인접한 문자열 리터럴 또한 같은 방식으로 연결된다, 아래 모든 경우, 인코딩 문자열과 접미사는 반드시 매치되어야 한다.
auto x1 = "hello" " " " world"; // OK
auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes
범용 문자 이름과 문자열 리터럴
네이티브(raw가 아닌) 문자열 리터럴은 범용 문자 이름이 하나 이상의 문자열 타입으로 인코딩 될수 있는 한 어떤 문자를 표현하기 위해서 범용 캐릭터 문자를 사용할 수도 있습니다. 예를 들어 확장 문자를 표현하는 범용문 자이름은 ansi 코드 페이지를 사용하는 좁은 문자열로 인코딩될 수 었습니다. 그러나 이것은 일부 멀티 바이트 코드 페이지나 utf8문자열 또는 넓은 문자열에서 좁은 문자열로 인코딩 될수 있습니다. c++11에서는 유니코드 서포토는 char16_t 그리고 char32_t 문자열 타입까지 확장되었습니다. 그리고 c++20은 char8_t까지 확장 시킵니다.
// ASCII smiling face
const char* s1 = ":-)";
// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)
const wchar_t* s2 = L"😉 = \U0001F609 is ;-)";
// UTF-8 encoded SMILING FACE WITH HALO (U+1F607)
const char* s3a = u8"😇 = \U0001F607 is O:-)"; // Before C++20
const char8_t* s3b = u8"😇 = \U0001F607 is O:-)"; // C++20
// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
const char16_t* s4 = u"😃 = \U0001F603 is :-D";
// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)
const char32_t* s5 = U"😎 = \U0001F60E is B-)";