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

Permite que los literales enteros, de punto flotante, de caracteres y de cadena produzcan objetos de tipo definido por el usuario mediante la definición de un sufijo definido por el usuario.

Contenidos

Sintaxis

Un literal definido por el usuario es una expresión de cualquiera de las siguientes formas

decimal-literal ud-suffix (1)
octal-literal ud-suffix (2)
hex-literal ud-suffix (3)
binary-literal ud-suffix (4)
fractional-constant exponent-part  (opcional) ud-suffix (5)
digit-sequence exponent-part ud-suffix (6)
character-literal ud-suffix (7)
string-literal ud-suffix (8)
1-4) literales enteros definidos por el usuario, tales como 12 _km
5-6) literales de punto flotante definidos por el usuario, tales como 0.5 _Pa
7) literal de carácter definido por el usuario, como 'c' _X
8) literal de cadena definido por el usuario, como "abd" _L o u "xyz" _M
decimal-literal - igual que en literal entero , un dígito decimal distinto de cero seguido de cero o más dígitos decimales
octal-literal - igual que en literal entero , un cero seguido de cero o más dígitos octales
hex-literal - igual que en literal entero , 0x o 0X seguido de uno o más dígitos hexadecimales
binary-literal - igual que en literal entero , 0b o 0B seguido de uno o más dígitos binarios
digit-sequence - igual que en literal de punto flotante , una secuencia de dígitos decimales
fractional-constant - igual que en literal de punto flotante , ya sea una digit-sequence seguida de un punto ( 123 . ) o una digit-sequence opcional seguida de un punto y otra digit-sequence ( 1.0 o .12 )
exponent-part - igual que en literal de punto flotante , la letra e o la letra E seguida de signo opcional, seguida de digit-sequence
character-literal - igual que en literal de carácter
string-literal - igual que en literal de cadena , incluyendo literales de cadena sin formato
ud-suffix - un identificador, introducido por una declaración de operador literal o plantilla de operador literal (ver abajo )

En las secuencias de dígitos de literales enteros y literales de punto flotante , se permiten separadores opcionales ' entre dos dígitos cualesquiera.

(desde C++14)

Si un token coincide con la sintaxis de literal definido por el usuario y con la sintaxis de literal regular, se asume que es un literal regular (es decir, es imposible sobrecargar LL en 123LL ).

Cuando el compilador encuentra un literal definido por el usuario con el ud-suffix X , realiza una búsqueda de nombre no calificada , buscando una función con el nombre operator "" X . Si la búsqueda no encuentra una declaración, el programa está mal formado. De lo contrario,

1) Para literales enteros definidos por el usuario,
a) si el conjunto de sobrecargas incluye un operador literal con el tipo de parámetro unsigned long long , la expresión literal definida por el usuario se trata como una llamada de función operator "" X ( n  ULL ) , donde n es el literal sin el sufijo-ud ;
b) de lo contrario, el conjunto de sobrecargas debe incluir, pero no ambos, un operador literal crudo o una plantilla de operador literal numérico. Si el conjunto de sobrecargas incluye un operador literal crudo, la expresión literal definida por el usuario se trata como una llamada a función operator "" X ( " n  ") ;
c) de lo contrario, si el conjunto de sobrecargas incluye una plantilla de operador literal numérico, la expresión de literal definido por el usuario se trata como una llamada de función operator "" X < ' c1  ' , ' c2  ' , ' c3  ' ..., ' ck  ' > ( ) , donde c1 .. ck son los caracteres individuales de n y todos ellos pertenecen al conjunto de caracteres básico .
2) Para literales de punto flotante definidos por el usuario,
a) Si el conjunto de sobrecarga incluye un operador literal con el tipo de parámetro long double , la expresión literal definida por el usuario se trata como una llamada de función operator "" X ( f   L ) , donde f es el literal sin el ud-suffix ;
b) de lo contrario, el conjunto de sobrecargas debe incluir, pero no ambos, un operador literal crudo o una plantilla de operador literal numérico. Si el conjunto de sobrecargas incluye un operador literal crudo, la expresión literal definida por el usuario se trata como una llamada a función operator "" X ( " f   ") ;
c) de lo contrario, si el conjunto de sobrecargas incluye una plantilla de operador literal numérico, la expresión literal definida por el usuario se trata como una llamada de función operator "" X < ' c1  ' , ' c2  ' , ' c3  ' ..., ' ck  ' > ( ) , donde c1 .. ck son los caracteres individuales de f y todos ellos pertenecen al conjunto de caracteres básico .
3) Para literales de cadena definidos por el usuario, sea str el literal sin el ud-suffix :
a) Si el conjunto de sobrecarga incluye una plantilla de operador de cadena literal con un parámetro de plantilla constante para el cual str es un argumento de plantilla válido, entonces la expresión de literal definida por el usuario se trata como una llamada de función operator "" X < str > ( ) ;
(desde C++20)
b) de lo contrario, la expresión de literal definido por el usuario se trata como una llamada a función operator "" X ( str, len ) , donde len es la longitud del literal de cadena, excluyendo el carácter nulo terminador.
4) Para literales de caracteres definidos por el usuario, la expresión literal definida por el usuario se trata como una llamada a función operator "" X ( ch ) , donde ch es el literal sin el 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;    // llama a operator ""_w(1.2L)
    u"one"_w; // llama a operator ""_w(u"one", 3)
    12_w;     // llama a operator ""_w("12")
    "two"_w;  // error: no hay un operador literal aplicable
}

Cuando la concatenación de literales de cadena tiene lugar en la fase de traducción 6 , los literales de cadena definidos por el usuario también se concatenan, y sus ud-suffix se ignoran para el propósito de concatenación, excepto que solo un sufijo puede aparecer en todos los literales concatenados:

int main()
{
    L"A" "B" "C"_x;  // OK: igual que L"ABC"_x
    "P"_x "Q" "R"_y; // error: dos sufijos de usuario diferentes (_x y _y)
}

Operadores literales

La función llamada por un literal definido por el usuario se conoce como literal operator (o, si es una plantilla, literal operator template ). Se declara como cualquier otra function o function template en el ámbito del espacio de nombres (también puede ser una función friend, una instanciación explícita o especialización de una plantilla de función, o introducida mediante una using-declaration), con excepción de las siguientes restricciones:

El nombre de esta función puede tener una de las dos formas:

operator "" identificador (1) (obsoleto)
operator literal-de-cadena-definido-por-el-usuario (2)
identifier - el identificador a utilizar como sufijo-ud para los literales definidos por el usuario que llamarán a esta función
user-defined-string-literal - la secuencia de caracteres "" seguida, sin espacio, por la secuencia de caracteres que se convierte en el sufijo-ud
1) Declara un literal operator.
2) Declara un operador literal. Esta sintaxis permite utilizar palabras clave del lenguaje e identificadores reservados como ud-suffix es, por ejemplo, operator "" if del encabezado <complex> .

ud-suffix debe comenzar con el guion bajo _ : los sufijos que no comienzan con el guion bajo están reservados para los operadores literales proporcionados por la biblioteca estándar. Tampoco puede contener dobles guiones bajos __ : dichos sufijos también están reservados.

Si el operador literal es una plantilla, debe tener una lista de parámetros vacía y solo puede tener un parámetro de plantilla, que debe ser un paquete de parámetros de plantilla constante con tipo de elemento char (en cuyo caso se conoce como plantilla de operador literal numérico ):

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

o un parámetro de plantilla constante de tipo clase (en cuyo caso se conoce como plantilla de operador de literal de cadena ):

struct A { constexpr A(const char*); };
template<A a>
A operator ""_a();
(desde C++20)

Solo se permiten las siguientes listas de parámetros en los operadores literales:

( const char * ) (1)
( unsigned long long int ) (2)
( long double ) (3)
( char ) (4)
( wchar_t ) (5)
( char8_t ) (6) (desde 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) (desde C++20)
( const char16_t * , std::size_t ) (12)
( const char32_t * , std::size_t ) (13)
1) Los operadores literales con esta lista de parámetros son los operadores literales sin formato , utilizados como respaldo para literales definidos por el usuario de enteros y punto flotante (ver arriba)
2) Los operadores literales con estas listas de parámetros son el operador literal de primera elección para literales enteros definidos por el usuario
3) Los operadores literales con estas listas de parámetros son el operador literal de primera elección para literales de punto flotante definidos por el usuario
4-8) Los operadores literales con estas listas de parámetros son llamados por literales de caracteres definidos por el usuario
9-13) Los operadores literales con estas listas de parámetros son llamados por literales de cadena definidos por el usuario

Argumentos predeterminados no están permitidos.

El language linkage de C no está permitido.

Aparte de las restricciones anteriores, los operadores literales y las plantillas de operadores literales son funciones normales (y plantillas de funciones), pueden declararse inline o constexpr, pueden tener vinculación interna o externa, pueden ser llamados explícitamente, se puede tomar sus direcciones, etc.

#include <string>
void        operator ""_km(long double); // OK, se llamará para 1.0_km
void        operator "" _km(long double); // igual al anterior, obsoleto
std::string operator ""_i18n(const char*, std::size_t); // OK
template<char...>
double operator ""_pi(); // OK
float  operator ""_e(const char*); // OK
// error: el sufijo debe comenzar con guion bajo
float operator ""Z(const char*);
// error: todos los nombres que comienzan con guion bajo seguido de letra mayúscula
// están reservados (NOTA: un espacio entre "" y _).
double operator"" _Z(long double);
// OK. NOTA: no hay espacio entre "" y _.
double operator""_Z(long double);
// OK: los operadores literales pueden sobrecargarse
double operator ""_Z(const char* args);
int main() {}

Notas

Desde la introducción de literales definidos por el usuario, el código que utiliza constantes de macro de formato para tipos enteros de ancho fijo sin espacio después del literal de cadena precedente se volvió inválido: std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; debe ser reemplazado por std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; .

Debido al maximal munch , los literales enteros y de punto flotante definidos por el usuario que terminan en p , P , (since C++17) e y E , cuando van seguidos de los operadores + o - , deben separarse del operador con espacios en blanco o paréntesis en el código fuente:

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

Lo mismo se aplica al operador punto que sigue a un literal definido por el usuario de tipo entero o de punto flotante:

#include <chrono>
using namespace std::literals;
auto a = 4s.count();   // Error
auto b = 4s .count();  // OK
auto c = (4s).count(); // OK

De lo contrario, se forma un único token de número de preprocesamiento inválido (por ejemplo, 1.0 _E + 2.0 o 4s. count ), lo que provoca que la compilación falle.

Macro de prueba de características Valor Std Característica
__cpp_user_defined_literals 200809L (C++11) Literales definidos por el usuario

Palabras clave

operator

Ejemplos

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numbers>
#include <string>
// utilizado como conversión de grados (parámetro de entrada) a radianes (salida devuelta)
constexpr long double operator""_deg_to_rad(long double deg)
{
    long double radians = deg * std::numbers::pi_v<long double> / 180;
    return radians;
}
// utilizado con tipo personalizado
struct mytype
{
    unsigned long long m;
};
constexpr mytype operator""_mytype(unsigned long long n)
{
    return mytype{n};
}
// utilizado para efectos secundarios
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';
}

Salida:

1.570796
123
0x123ABC
abcabc

Biblioteca estándar

Los siguientes operadores literales están definidos en la biblioteca estándar:

Definido en el espacio de nombres en línea std::literals::complex_literals
un literal std::complex que representa un número puramente imaginario
(función)
Definido en el espacio de nombres en línea std::literals::chrono_literals
un literal std::chrono::duration que representa horas
(función)
un literal std::chrono::duration que representa minutos
(función)
un literal std::chrono::duration que representa segundos
(función)
un literal std::chrono::duration que representa milisegundos
(función)
un literal std::chrono::duration que representa microsegundos
(función)
un literal std::chrono::duration que representa nanosegundos
(función)
un literal std::chrono::year que representa un año particular
(función)
un literal std::chrono::day que representa un día del mes
(función)
Definido en el espacio de nombres en línea std::literals::string_literals
convierte un literal de arreglo de caracteres a basic_string
(función)
Definido en el espacio de nombres en línea std::literals::string_view_literals
crea una vista de cadena de un literal de arreglo de caracteres
(función)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Se aplica a Comportamiento publicado Comportamiento correcto
CWG 1473 C++11 se requería espacio en blanco entre "" y ud-suffix en la
declaración de operadores literales
se hizo opcional
CWG 1479 C++11 los operadores literales podían tener argumentos predeterminados prohibido
CWG 2521 C++11 operator "" _Bq estaba mal formado (no se requería
diagnóstico) porque usa el identificador reservado _Bq
se deprecó la sintaxis del operador literal
con espacio en blanco entre "" y ud-suffix