Spec-Zone.ru › C++

Пользовательские литералы (начиная с 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)
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 - идентификатор, вводимый объявлением оператора литерала или шаблона оператора литерала (см. ниже)

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

(начиная с C++14)

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

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

1) Для пользовательских целочисленных литералов:
a) если набор перегрузок включает оператор литерала с типом параметра unsignedlonglong, выражение пользовательского литерала рассматривается как вызов функции operator ""X(n ULL), где n — литерал без ud-suffix;
b) в противном случае набор перегрузок должен включать либо сырой оператор литерала, либо шаблон числового оператора литерала, но не оба сразу. Если набор перегрузок включает сырой оператор литерала, выражение пользовательского литерала рассматривается как вызов функции operator""X("n ");
c) в противном случае, если набор перегрузок включает шаблон числового оператора литерала, выражение пользовательского литерала рассматривается как вызов функции operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы n, каждый из которых принадлежит базовому набору символов.
2) Для пользовательских литералов с плавающей точкой:
a) если набор перегрузок включает оператор литерала с типом параметра longdouble, выражение пользовательского литерала рассматривается как вызов функции operator ""X(f  L), где f — литерал без ud-suffix;
b) в противном случае набор перегрузок должен включать либо сырой оператор литерала, либо шаблон числового оператора литерала, но не оба сразу. Если набор перегрузок включает сырой оператор литерала, выражение пользовательского литерала рассматривается как вызов функции operator ""X("f  ");
c) в противном случае, если набор перегрузок включает шаблон числового оператора литерала, выражение пользовательского литерала рассматривается как вызов функции operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы f, каждый из которых принадлежит базовому набору символов.
3) Для пользовательских строковых литералов пусть str — литерал без ud-suffix:
a) если набор перегрузок включает шаблон оператора строкового литерала с нетиповым параметром шаблона, для которого str является корректным аргументом шаблона, выражение пользовательского литерала рассматривается как вызов функции operator ""X<str>(); (начиная с C++20)
b) в противном случае выражение пользовательского литерала рассматривается как вызов функции operator ""X (str, len), где len — длина строкового литерала без завершающего нулевого символа.
4) Для пользовательских символьных литералов выражение пользовательского литерала рассматривается как вызов функции 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
1) Объявляет оператор литерала.
2) Объявляет оператор литерала. Этот синтаксис позволяет использовать ключевые слова языка и зарезервированные идентификаторы в качестве суффиксов ud-suffix, например, operator""if из заголовка <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)
1) Операторы литералов с таким списком параметров являются сырыми операторами литералов, используемыми как запасной вариант для пользовательских целочисленных литералов и литералов с плавающей точкой (см. выше)
2) Операторы литералов с такими списками параметров являются предпочтительными операторами литералов для пользовательских целочисленных литералов
3) Операторы литералов с такими списками параметров являются предпочтительными операторами литералов для пользовательских литералов с плавающей точкой
4-8) Операторы литералов с такими списками параметров вызываются пользовательскими символьными литералами
9-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) Пользовательские литералы

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

operator

Примеры

#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
operator""ifoperator""ioperator""il
(C++14)
литерал типа std::complex, представляющий чисто мнимое число
(функция)
Определены во встроенном пространстве имен std::literals::chrono_literals
operator""h
(C++14)
литерал типа std::chrono::duration, представляющий часы
(функция)
operator""min
(C++14)
литерал типа std::chrono::duration, представляющий минуты
(функция)
operator""s
(C++14)
литерал типа std::chrono::duration, представляющий секунды
(функция)
operator""ms
(C++14)
литерал типа std::chrono::duration, представляющий миллисекунды
(функция)
operator""us
(C++14)
литерал типа std::chrono::duration, представляющий микросекунды
(функция)
operator""ns
(C++14)
литерал типа std::chrono::duration, представляющий наносекунды
(функция)
operator""y
(C++20)
литерал типа std::chrono::year, представляющий определенный год
(функция)
operator""d
(C++20)
литерал типа std::chrono::day, представляющий день месяца
(функция)
Определены во встроенном пространстве имен std::literals::string_literals
operator""s
(C++14)
преобразует литерал-массив символов в basic_string
(функция)
Определены во встроенном пространстве имен std::literals::string_view_literals
operator""sv
(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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API