Пользовательские литералы (начиная с C++11)
Позволяют целочисленным, литералам с плавающей точкой, символьным и строковым литералам создавать объекты пользовательского типа посредством определения пользовательского суффикса.
Синтаксис
Пользовательский литерал представляет собой выражение одной из следующих форм
| decimal-literal ud-suffix | (1) | |
| octal-literal ud-suffix | (2) | |
| hex-literal ud-suffix | (3) | |
| binary-literal ud-suffix | (4) | |
| fractional-constant exponent-part (необязательно) ud-suffix | (5) | |
| digit-sequence exponent-part ud-suffix | (6) | |
| character-literal ud-suffix | (7) | |
| string-literal ud-suffix | (8) |
12_km
0.5_Pa
'c'_X
"abd"_L или u"xyz"_M
| decimal-literal | - | то же, что и в целочисленном литерале: ненулевая десятичная цифра, за которой следует ноль или более десятичных цифр |
| octal-literal | - | то же, что и в целочисленном литерале: ноль, за которым следует ноль или более восьмеричных цифр |
| hex-literal | - | то же, что и в целочисленном литерале: 0x или 0X, за которыми следует одна или более шестнадцатеричных цифр |
| binary-literal | - | то же, что и в целочисленном литерале: 0b или 0B, за которыми следует одна или более двоичных цифр |
| digit-sequence | - | то же, что и в литерале с плавающей точкой: последовательность десятичных цифр |
| fractional-constant | - | то же, что и в литерале с плавающей точкой: либо digit-sequence, за которой следует точка (123.), либо необязательная digit-sequence, за которой следует точка и еще одна digit-sequence (1.0 или .12) |
| exponent-part | - | то же, что и в литерале с плавающей точкой: буква e или буква E, за которой следует необязательный знак, а затем digit-sequence |
| character-literal | - | то же, что и в символьном литерале |
| string-literal | - | то же, что и в строковом литерале, включая необработанные строковые литералы |
| ud-suffix | - | идентификатор, вводимый объявлением оператора литерала или шаблона оператора литерала (см. ниже) |
| В последовательностях цифр целочисленных и вещественных литералов между любыми двумя цифрами допускаются необязательные разделители | (начиная с C++14) |
Если токен соответствует синтаксису пользовательского литерала и синтаксису обычного литерала, он считается обычным литералом (то есть перегрузить LL в 123LL невозможно).
Когда компилятор встречает пользовательский литерал с суффиксом ud-suffix X, он выполняет поиск неквалифицированного имени, разыскивая функцию с именем operator""X. Если поиск не находит объявления, программа некорректна. В противном случае:
operator ""X(n ULL), где n — литерал без ud-suffix;operator""X("n ");operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы n, каждый из которых принадлежит базовому набору символов.operator ""X(f L), где f — литерал без ud-suffix;operator ""X("f ");operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы f, каждый из которых принадлежит базовому набору символов.str — литерал без ud-suffix: a) если набор перегрузок включает шаблон оператора строкового литерала с нетиповым параметром шаблона, для которого str является корректным аргументом шаблона, выражение пользовательского литерала рассматривается как вызов функции operator ""X<str>(); | (начиная с C++20) |
operator ""X (str, len), где len — длина строкового литерала без завершающего нулевого символа.operator ""X(ch), где ch — литерал без ud-suffix.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-suffix игнорируются при конкатенации, за исключением того, что для всех конкатенируемых литералов может быть указан только один суффикс:
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 "" identifier | (1) | (устарело) |
operator user-defined-string-literal | (2) |
| identifier | - | идентификатор, используемый в качестве ud-suffix пользовательских литералов, которые будут вызывать эту функцию |
| user-defined-string-literal | - | последовательность символов "", за которой без пробела следует последовательность символов, образующая ud-suffix |
<complex>.ud-suffix должен начинаться с символа подчёркивания _: суффиксы, не начинающиеся с подчёркивания, зарезервированы для операторов литералов стандартной библиотеки. Он также не может содержать двойное подчёркивание __: такие суффиксы также зарезервированы.
Если оператор литерала является шаблоном, он должен иметь пустой список параметров и может иметь только один параметр шаблона, который должен быть пакетом нетиповых параметров шаблона с типом элемента char (в этом случае он называется шаблоном числового оператора литерала):
template<char...> double operator ""_x();
| или нетиповым параметром шаблона классового типа (в этом случае он называется шаблоном оператора строкового литерала): struct A { constexpr A(const char*); };
template<A a>
A operator ""_a();
| (начиная с C++20) |
Для операторов литералов допускаются только следующие списки параметров:
( constchar* ) | (1) | |
( unsignedlonglongint ) | (2) | |
( longdouble ) | (3) | |
( char ) | (4) | |
( wchar_t ) | (5) | |
( char8_t ) | (6) | (начиная с C++20) |
( char16_t ) | (7) | |
( char32_t ) | (8) | |
( constchar*, std::size_t ) | (9) | |
( constwchar_t*, std::size_t ) | (10) | |
( constchar8_t*, std::size_t ) | (11) | (начиная с C++20) |
( constchar16_t*, std::size_t ) | (12) | |
( constchar32_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/cpp/language/user_literal