Определяемые пользователем литералы (с C++11)
Разрешает целые, вещественные, символьные и строковые литералы для создания объектов определённого пользователем типа, определяя пользовательский суффикс.
Синтаксис
Определяемый пользователем литерал — это выражение любого из следующих видов
| десятичный-литерал ud-суффикс | (1) | |
| восьмеричный-литерал ud-суффикс | (2) | |
| шестнадцатеричный-литерал ud-суффикс | (3) | |
| двоичный-литерал ud-суффикс | (4) | |
| дробное-постоянное-значение экспоненциальная-часть (необязательно) ud-суффикс | (5) | |
| последовательность-цифр экспоненциальная-часть ud-суффикс | (6) | |
| символьный-литерал ud-суффикс | (7) | |
| строковый-литерал ud-суффикс | (8) |
12_km
0.5_Pa
'c'_X
"abd"_L или u"xyz"_M
| десятичный-литерал | - | такое же, как в литерале целого числа, не нулевая десятичная цифра, за которой следует ноль или более десятичных цифр |
| восьмеричный-литерал | - | такое же, как в литерале целого числа, ноль, за которым следуют ноль или более восьмеричных цифр |
| шестнадцатеричный-литерал | - | такое же, как в литерале целого числа, 0x или 0X, за которыми следуют одна или более шестнадцатеричных цифр |
| двоичный-литерал | - | такое же, как в литерале целого числа, 0b или 0B, за которыми следуют одна или более двоичных цифр |
| последовательность-цифр | - | такое же, как в литерале с плавающей точкой, последовательность десятичных цифр |
| дробное-постоянное-значение | - | такое же, как в литерале с плавающей точкой, либо последовательность-цифр, за которой следует точка (123.) или необязательная последовательность-цифр, за которой следует точка и другая последовательность-цифр (1.0 или .12) |
| экспоненциальная-часть | - | такое же, как в литерале с плавающей точкой, буква e или буква E , за которой следует необязательный знак, за которым следует последовательность-цифр |
| символьный-литерал | - | такое же, как в символьном литерале |
| строковый-литерал | - | такое же, как в строковом литерале, включая сырые строковые литералы |
| ud-суффикс | - | идентификатор, введённый объявлением оператора литерала или шаблона оператора литерала (см. ниже) |
| В целых и вещественных последовательностях цифр разрешены необязательные разделители | (с C++14) |
Если токен соответствует синтаксису определяемого пользователем литерала и обычному синтаксису литерала, предполагается, что это обычный литерал (то есть перегрузка LL в 123LL невозможна).
Когда компилятор встречает определяемый пользователем литерал с ud-суффиксом X, он выполняет поиск неквалифицированного имени, ища функцию с именем operator""X. Если поиск не находит объявление, программа недействительна. В противном случае,
unsigned long long, выражение определяемого пользователем литерала обрабатывается как вызов функции operator ""X(n ULL), где n — литерал без ud-суффикса;operator""X("n ");operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы n, и все они из базового набора символов.long double, выражение определяемого пользователем литерала обрабатывается как вызов функции operator ""X(f L), где f — литерал без ud-суффикса;operator ""X("f ");operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы f, и все они из базового набора символов.str — литерал без ud-суффикса: a) Если набор перегрузок включает шаблон оператора строкового литерала с параметром шаблона без типа, для которого str является корректным аргументом шаблона, то выражение определяемого пользователем литерала обрабатывается как вызов функции operator ""X<str>(); | (с C++20) |
operator ""X (str, len), где len — длина строкового литерала без терминального нулевого символа.operator ""X(ch), где ch — литерал без ud-суффикса.long double operator ""_w(long double);
std::string operator ""_w(const char16_t*, size_t);
unsigned operator ""_w(const char*);
int main()
{
1.2_w; // calls operator ""_w(1.2L)
u"one"_w; // calls operator ""_w(u"one", 3)
12_w; // calls operator ""_w("12")
"two"_w; // error: no applicable literal operator
}Когда происходит конкатенация строковых литералов в фазе 6 трансляции, определяемые пользователем строковые литералы конкатенируются также, и их ud-суффиксы игнорируются для целей конкатенации, за исключением того, что только один суффикс может появиться на всех конкатенированных литералах:
int main()
{
L"A" "B" "C"_x; // OK: same as L"ABC"_x
"P"_x "Q" "R"_y; // error: two different ud-suffixes (_x and _y)
}Операторы литералов
Функция, вызываемая определяемым пользователем литералом, известна как оператор литерала (или, если это шаблон, шаблон оператора литерала). Она объявляется так же, как любая другая функция или шаблон функции в области видимости пространства имён (она также может быть дружественной функцией, явной инстанциацией или специализацией шаблона функции или введена с помощью using-объявления), за исключением следующих ограничений:
Имя этой функции может иметь один из двух форм:
operator "" идентификатор | (1) | (устарело) |
operator строковый-литерал-определённый-пользователем | (2) |
| идентификатор | - | используемый идентификатор в качестве суффикса_ud для пользовательских литералов, вызывающих эту функцию |
| пользовательский_литерал_строки | - | последовательность символов "" , за которой без пробела следует последовательность символов, становящаяся суффиксом_ud |
operator ""if из заголовка <complex>.суффикс_ud должен начинаться с подчеркивания _: суффиксы, не начинающиеся с подчеркивания, зарезервированы для операторов литералов, предоставляемых стандартной библиотекой. Он также не может содержать двойные подчеркивания __: такие суффиксы также зарезервированы.
Если оператор литерала является шаблоном, он должен иметь пустой список параметров и может иметь только один параметр шаблона, который должен быть упакованным параметром шаблона без типа со значением типа char (в этом случае он известен как шаблон оператора числового литерала):
template<char...> double operator ""_x();
| или параметр шаблона без типа с типом класса (в этом случае он известен как шаблон оператора строкового литерала): struct A { constexpr A(const char*); };
template<A a>
A operator ""_a(); | (с C++20) |
Разрешены только следующие списки параметров для операторов литералов:
( const char* ) | (1) | |
( unsigned long long int ) | (2) | |
( long double ) | (3) | |
( char ) | (4) | |
( wchar_t ) | (5) | |
( char8_t ) | (6) | (с C++20) |
( char16_t ) | (7) | |
( char32_t ) | (8) | |
( const char*, std::size_t ) | (9) | |
( const wchar_t*, std::size_t ) | (10) | |
( const char8_t*, std::size_t ) | (11) | (с C++20) |
( const char16_t*, std::size_t ) | (12) | |
( const char32_t*, std::size_t ) | (13) |
Значения аргументов по умолчанию не допускаются.
Связь языка C не допускается.
Помимо вышеперечисленных ограничений, операторы литералов и шаблоны операторов литералов являются обычными функциями (и шаблонами функций), они могут быть объявлены inline или constexpr, они могут иметь внутреннюю или внешнюю связь, они могут быть вызваны явно, к ним можно получить доступ по адресу и т.д.
#include <string>
void operator ""_km(long double); // OK, will be called for 1.0_km
void operator "" _km(long double); // same as above, deprecated
std::string operator ""_i18n(const char*, std::size_t); // OK
template<char...>
double operator ""_pi(); // OK
float operator ""_e(const char*); // OK
// error: suffix must begin with underscore
float operator ""Z(const char*);
// error: all names that begin with underscore followed by uppercase
// letter are reserved (NOTE: a space between "" and _).
double operator"" _Z(long double);
// OK. NOTE: no space between "" and _.
double operator""_Z(long double);
// OK: literal operators can be overloaded
double operator ""_Z(const char* args);
int main() {}Примечания
После введения пользовательских литералов код, использующий константы макросов формата для типов целых чисел с фиксированной шириной без пробела после предшествующего литерала строки, стал недопустимым: std::printf("%"PRId64"\n",INT64_MIN); необходимо заменить на std::printf("%" PRId64"\n",INT64_MIN);.
Из-за максимального разбора, пользовательские литералы целых и чисел с плавающей точкой, заканчивающиеся p, P,(с C++17) e и E, если за ними следуют операторы + или -, должны быть отделены от оператора пробелом или скобками в исходном коде:
long double operator""_E(long double); long double operator""_a(long double); int operator""_p(unsigned long long); auto x = 1.0_E+2.0; // error auto y = 1.0_a+2.0; // OK auto z = 1.0_E +2.0; // OK auto q = (1.0_E)+2.0; // OK auto w = 1_p+2; // error auto u = 1_p +2; // OK
То же самое относится к оператору точки, следующему за пользовательским литералом целого или числа с плавающей точкой:
#include <chrono> using namespace std::literals; auto a = 4s.count(); // Error auto b = 4s .count(); // OK auto c = (4s).count(); // OK
В противном случае формируется один недопустимый токен предобработки числа (например, 1.0_E+2.0 или 4s.count), что приводит к ошибке компиляции.
| Макросы тестирования функций | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_user_defined_literals | 200809L | (C++11) | Пользовательские литералы |
Примеры
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numbers>
#include <string>
// used as conversion from degrees (input param) to radians (returned output)
constexpr long double operator""_deg_to_rad(long double deg)
{
long double radians = deg * std::numbers::pi_v<long double> / 180;
return radians;
}
// used with custom type
struct mytype
{
unsigned long long m;
};
constexpr mytype operator""_mytype(unsigned long long n)
{
return mytype{n};
}
// used for side-effects
void operator""_print(const char* str)
{
std::cout << str << '\n';
}
#if __cpp_nontype_template_args < 201911
std::string operator""_x2 (const char* str, std::size_t)
{
return std::string{str} + str;
}
#else // C++20 string literal operator template
template<std::size_t N>
struct DoubleString
{
char p[N + N - 1]{};
constexpr DoubleString(char const(&pp)[N])
{
std::ranges::copy(pp, p);
std::ranges::copy(pp, p + N - 1);
}
};
template<DoubleString A>
constexpr auto operator""_x2()
{
return A.p;
}
#endif // C++20
int main()
{
double x_rad = 90.0_deg_to_rad;
std::cout << std::fixed << x_rad << '\n';
mytype y = 123_mytype;
std::cout << y.m << '\n';
0x123ABC_print;
std::cout << "abc"_x2 << '\n';
}Вывод:
1.570796 123 0x123ABC abcabc
Стандартная библиотека
Следующие операторы литералов определены в стандартной библиотеке:
Определено в встроенном именованном пространстве std::literals::complex_literals |
|
|---|---|
|
(C++14) | буквенная константа std::complex представляющая чисто мнимое число (функция) |
Определено в встроенном именованном пространстве std::literals::chrono_literals |
|
|
(C++14) | буквенная константа std::chrono::duration представляющая часы (функция) |
|
(C++14) | буквенная константа std::chrono::duration представляющая минуты (функция) |
|
(C++14) | буквенная константа std::chrono::duration представляющая секунды (функция) |
|
(C++14) | буквенная константа std::chrono::duration представляющая миллисекунды (функция) |
|
(C++14) | буквенная константа std::chrono::duration представляющая микросекунды (функция) |
|
(C++14) | буквенная константа std::chrono::duration представляющая наносекунды (функция) |
|
(C++20) | буквенная константа std::chrono::year представляющая конкретный год (функция) |
|
(C++20) | буквенная константа std::chrono::day представляющая день месяца (функция) |
Определено в встроенном именованном пространстве std::literals::string_literals |
|
|
(C++14) | преобразует буквенную константу массива символов в basic_string (функция) |
Определено в встроенном именованном пространстве std::literals::string_view_literals |
|
|
(C++17) | создаёт представление строки из буквенной константы массива символов (функция) |
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение при публикации | Корректное поведение |
|---|---|---|---|
| CWG 1473 | C++11 | пробелы между "" и ud-suffix были требовались в объявлении операторов литералов | стали необязательными |
| CWG 1479 | C++11 | операторы литералов могли иметь аргументы по умолчанию | запрещены |
| CWG 2521 | C++11 | operator"" _Bq было некорректным (не требуется диагностика ), так как оно использует зарезервированное идентификатор _Bq | синтаксис оператора литерала стал устаревшим с пробелами между "" и ud-suffix |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/user_literal