Namespaces
Variants

User-defined literals (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Позволяет целочисленным, вещественным, символьным и строковым литералам создавать объекты пользовательского типа путем определения пользовательского суффикса.

Содержание

Синтаксис

Пользовательский литерал — это выражение одного из следующих видов

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)
1-4) пользовательские целочисленные литералы, такие как 12 _km
5-6) пользовательские литералы с плавающей точкой, такие как 0.5 _Pa
7) пользовательский символьный литерал, например 'c' _X
8) пользовательский строковый литерал, такой как "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 - идентификатор, вводимый объявлением литерального оператора или шаблона литерального оператора (см. ниже )

В последовательностях цифр целочисленных и чисел с плавающей точкой , необязательные разделители ' разрешены между любыми двумя цифрами.

(since C++14)

Если токен соответствует синтаксису пользовательского литерала и синтаксису обычного литерала, считается, что это обычный литерал (то есть невозможно перегрузить LL в 123LL ).

Когда компилятор встречает пользовательский литерал с ud-суффиксом X , он выполняет поиск по неквалифицированному имени , ища функцию с именем operator "" X . Если поиск не находит объявление, программа является некорректной. В противном случае,

1) Для пользовательских целочисленных литералов,
а) если набор перегрузок включает литеральный оператор с типом параметра unsigned long long , пользовательское литеральное выражение обрабатывается как вызов функции operator "" X ( n  ULL ) , где n представляет собой литерал без ud-суффикса ;
b) в противном случае набор перегрузок должен включать либо, но не оба, необработанный литеральный оператор или шаблон числового литерального оператора. Если набор перегрузок включает необработанный литеральный оператор, пользовательский литерал рассматривается как вызов функции operator "" X ( " n  ") ;
c) в противном случае, если набор перегрузок включает шаблон числового литерального оператора, пользовательский литерал рассматривается как вызов функции operator "" X < ' c1  ' , ' c2  ' , ' c3  ' ..., ' ck  ' > ( ) , где c1 .. ck являются отдельными символами n и все они принадлежат базовому набору символов .
2) Для пользовательских литералов с плавающей точкой,
а) Если набор перегрузок включает литеральный оператор с типом параметра long double , пользовательское литеральное выражение обрабатывается как вызов функции operator "" X ( f   L ) , где f представляет собой литерал без ud-суффикса ;
б) в противном случае набор перегрузок должен включать либо, но не оба, необработанный литеральный оператор или шаблон числового литерального оператора. Если набор перегрузок включает необработанный литеральный оператор, пользовательский литерал рассматривается как вызов функции operator "" X ( " f   ") ;
c) в противном случае, если набор перегрузок включает шаблон числового литерального оператора, пользовательский литерал рассматривается как вызов функции operator "" X < ' c1  ' , ' c2  ' , ' c3  ' ..., ' ck  ' > ( ) , где c1 .. ck являются отдельными символами f и все они принадлежат базовому набору символов .
3) Для пользовательских строковых литералов, пусть str будет литералом без ud-суффикса :
a) Если набор перегрузок включает шаблон литерального оператора строки с константным параметром шаблона, для которого str является корректным аргументом шаблона, то пользовательский литерал рассматривается как вызов функции operator "" X < str > ( ) ;
(начиная с C++20)
b) в противном случае, выражение пользовательского литерала трактуется как вызов функции operator "" X ( str, len ) , где len — длина строкового литерала, исключая завершающий нулевой символ.
4) Для пользовательских символьных литералов пользовательское литеральное выражение трактуется как вызов функции 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;    // вызывает operator ""_w(1.2L)
    u"one"_w; // вызывает operator ""_w(u"one", 3)
    12_w;     // вызывает operator ""_w("12")
    "two"_w;  // ошибка: нет подходящего литерального оператора
}

Когда конкатенация строковых литералов происходит на фазе трансляции 6 , пользовательские строковые литералы также конкатенируются, и их ud-суффиксы игнорируются для целей конкатенации, за исключением того, что только один суффикс может присутствовать на всех объединённых литералах:

int main()
{
    L"A" "B" "C"_x;  // OK: то же самое, что L"ABC"_x
    "P"_x "Q" "R"_y; // ошибка: два разных пользовательских суффикса (_x и _y)
}

Литеральные операторы

Функция, вызываемая пользовательским литералом, называется literal operator (или, если это шаблон, literal operator template ). Она объявляется так же, как любая другая function или function template в области видимости пространства имён (она также может быть функцией-другом, явным инстанцированием или специализацией шаблона функции, или введена через using-декларацию), за исключением следующих ограничений:

Название этой функции может иметь одну из двух форм:

operator "" identifier (1) (устарело)
operator user-defined-string-literal (2)
identifier - идентификатор, который будет использоваться в качестве ud-suffix для пользовательских литералов, вызывающих данную функцию
user-defined-string-literal - последовательность символов "" с последующей (без пробела) последовательностью символов, которая становится ud-suffix
1) Объявляет литеральный оператор.
2) Объявляет литеральный оператор. Данный синтаксис позволяет использовать ключевые слова языка и зарезервированные идентификаторы в качестве ud-suffix ов, например, operator "" if из заголовка <complex> .

ud-суффикс должен начинаться с подчеркивания _ : суффиксы, которые не начинаются с подчеркивания, зарезервированы для литеральных операторов, предоставляемых стандартной библиотекой. Он также не может содержать двойных подчеркиваний __ : такие суффиксы также зарезервированы.

Если литеральный оператор является шаблоном, он должен иметь пустой список параметров и может иметь только один шаблонный параметр, который должен быть константным шаблонным параметром-пакетом с типом элементов char (в этом случае он известен как numeric literal operator template ):

template<char...>
double operator ""_x();

или параметр шаблона константного типа класса (в этом случае он известен как шаблонный оператор строкового литерала ):

struct A { constexpr A(const char*); };
template<A a>
A operator ""_a();
(since 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)
1) Литеральные операторы с этим списком параметров являются сырыми литеральными операторами , используемыми как резервные варианты для целочисленных и дробных пользовательских литералов (см. выше)
2) Литеральные операторы с этими списками параметров являются операторами первого выбора для пользовательских целочисленных литералов
3) Литеральные операторы с этими списками параметров являются операторами первого выбора для пользовательских литералов с плавающей точкой
4-8) Литеральные операторы с этими списками параметров вызываются пользовательскими символьными литералами
9-13) Литеральные операторы с этими списками параметров вызываются пользовательскими строковыми литералами

Аргументы по умолчанию не допускаются.

Связи языка C language linkage не допускаются.

Помимо указанных выше ограничений, литеральные операторы и шаблоны литеральных операторов являются обычными функциями (и шаблонами функций): они могут быть объявлены как inline или constexpr, могут иметь внутреннюю или внешнюю линковку, могут быть вызваны явно, их адреса могут быть взяты и т.д.

#include <string>
void        operator ""_km(long double); // OK, будет вызван для 1.0_km
void        operator "" _km(long double); // то же самое, устаревший вариант
std::string operator ""_i18n(const char*, std::size_t); // OK
template<char...>
double operator ""_pi(); // OK
float  operator ""_e(const char*); // OK
// ошибка: суффикс должен начинаться с подчеркивания
float operator ""Z(const char*);
// ошибка: все имена, начинающиеся с подчеркивания и следующей заглавной
// буквы, зарезервированы (ПРИМЕЧАНИЕ: пробел между "" и _)
double operator"" _Z(long double);
// OK. ПРИМЕЧАНИЕ: нет пробела между "" и _
double operator""_Z(long double);
// OK: литеральные операторы могут быть перегружены
double operator ""_Z(const char* args);
int main() {}

Примечания

С момента введения пользовательских литералов код, использующий макроконстанты формата для целочисленных типов фиксированной ширины без пробела после предшествующего строкового литерала, стал некорректным: std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; должен быть заменён на std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; .

Из-за максимального поглощения , пользовательские целочисленные и литералы с плавающей точкой, оканчивающиеся на p , P , (since 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;   // ошибка
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;       // ошибка
auto u = 1_p +2;      // OK

То же самое относится к оператору точки, следующему за целочисленным или плавающим пользовательским литералом:

#include <chrono>
using namespace std::literals;
auto a = 4s.count();   // Ошибка
auto b = 4s .count();  // OK
auto c = (4s).count(); // OK

В противном случае формируется единственный некорректный токен препроцессорного числа (например, 1.0 _E + 2.0 или 4s. count ), что приводит к ошибке компиляции.

Макроопределение для проверки функциональности Значение Стандарт Функциональность
__cpp_user_defined_literals 200809L (C++11) Пользовательские литералы

Ключевые слова

operator

Примеры

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numbers>
#include <string>
// используется для преобразования градусов (входной параметр) в радианы (возвращаемое значение)
constexpr long double operator""_deg_to_rad(long double deg)
{
    long double radians = deg * std::numbers::pi_v<long double> / 180;
    return radians;
}
// используется с пользовательским типом
struct mytype
{
    unsigned long long m;
};
constexpr mytype operator""_mytype(unsigned long long n)
{
    return mytype{n};
}
// используется для побочных эффектов
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
литерал std::complex представляющий чисто мнимое число
(функция)
Определено во встроенном пространстве имен std::literals::chrono_literals
литерал std::chrono::duration представляющий часы
(функция)
литерал std::chrono::duration представляющий минуты
(функция)
литерал std::chrono::duration представляющий секунды
(функция)
литерал std::chrono::duration представляющий миллисекунды
(функция)
литерал std::chrono::duration представляющий микросекунды
(функция)
литерал std::chrono::duration представляющий наносекунды
(функция)
литерал std::chrono::year представляющий конкретный год
(функция)
литерал std::chrono::day представляющий день месяца
(функция)
Определено во встроенном пространстве имен std::literals::string_literals
преобразует литерал массива символов в basic_string
(функция)
Определено во встроенном пространстве имен std::literals::string_view_literals
создает string_view из литерала массива символов
(функция)

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 1473 C++11 пробел между "" и ud-suffix был
обязателен в объявлении литеральных операторов
сделан опциональным
CWG 1479 C++11 литеральные операторы могли иметь аргументы по умолчанию запрещено
CWG 2521 C++11 operator "" _Bq был некорректным (диагностика не
требовалась), так как использует зарезервированный идентификатор _Bq
устарел синтаксис литерального оператора
с пробелом между "" и ud-suffix