Spec-Zone.ru › C++

Определяемые пользователем литералы (с C++11)

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

Синтаксис

Определяемый пользователем литерал — это выражение любого из следующих видов

десятичный-литерал ud-суффикс (1)
восьмеричный-литерал ud-суффикс (2)
шестнадцатеричный-литерал ud-суффикс (3)
двоичный-литерал ud-суффикс (4)
дробное-постоянное-значение экспоненциальная-часть (необязательно) ud-суффикс (5)
последовательность-цифр экспоненциальная-часть ud-суффикс (6)
символьный-литерал ud-суффикс (7)
строковый-литерал ud-суффикс (8)
1-4) литералы целых чисел, определяемых пользователем, такие как 12_km
5-6) литералы с плавающей точкой, определяемые пользователем, такие как 0.5_Pa
7) символьный литерал, определяемый пользователем, такой как 'c'_X
8) строковый литерал, определяемый пользователем, такой как "abd"_L или u"xyz"_M
десятичный-литерал - такое же, как в литерале целого числа, не нулевая десятичная цифра, за которой следует ноль или более десятичных цифр
восьмеричный-литерал - такое же, как в литерале целого числа, ноль, за которым следуют ноль или более восьмеричных цифр
шестнадцатеричный-литерал - такое же, как в литерале целого числа, 0x или 0X, за которыми следуют одна или более шестнадцатеричных цифр
двоичный-литерал - такое же, как в литерале целого числа, 0b или 0B, за которыми следуют одна или более двоичных цифр
последовательность-цифр - такое же, как в литерале с плавающей точкой, последовательность десятичных цифр
дробное-постоянное-значение - такое же, как в литерале с плавающей точкой, либо последовательность-цифр, за которой следует точка (123.) или необязательная последовательность-цифр, за которой следует точка и другая последовательность-цифр (1.0 или .12)
экспоненциальная-часть - такое же, как в литерале с плавающей точкой, буква e или буква E , за которой следует необязательный знак, за которым следует последовательность-цифр
символьный-литерал - такое же, как в символьном литерале
строковый-литерал - такое же, как в строковом литерале, включая сырые строковые литералы
ud-суффикс - идентификатор, введённый объявлением оператора литерала или шаблона оператора литерала (см. ниже)

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

(с C++14)

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

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

1) Для литералов целых чисел, определяемых пользователем,
a) если набор перегрузок включает оператор литерала с типом параметра unsigned long long, выражение определяемого пользователем литерала обрабатывается как вызов функции operator ""X(n ULL), где n — литерал без ud-суффикса;
b) в противном случае, набор перегрузок должен включать либо, но не оба, оператор сырого литерала или шаблон оператора числового литерала. Если набор перегрузок включает оператор сырого литерала, выражение определяемого пользователем литерала обрабатывается как вызов функции operator""X("n ");
c) в противном случае, если набор перегрузок включает шаблон оператора числового литерала, выражение определяемого пользователем литерала обрабатывается как вызов функции operator""X<'c1 ', 'c2 ', 'c3 '..., 'ck '>(), где c1..ck — отдельные символы n, и все они из базового набора символов.
2) Для литералов с плавающей точкой, определяемых пользователем,
a) Если набор перегрузок включает оператор литерала с типом параметра long double, выражение определяемого пользователем литерала обрабатывается как вызов функции operator ""X(f  L), где f — литерал без ud-суффикса;
b) в противном случае, набор перегрузок должен включать либо, но не оба, оператор сырого литерала или шаблон оператора числового литерала. Если набор перегрузок включает оператор сырого литерала, выражение определяемого пользователем литерала обрабатывается как вызов функции 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;    // 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
1) Объявляет оператор литерала.
2) Объявляет оператор литерала. Этот синтаксис позволяет использовать ключевые слова языка и зарезервированные идентификаторы в качестве суффикса_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)
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) Пользовательские литералы

Примеры

#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/w/cpp/language/user_literal

Spec-Zone.ru

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