Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Пользовательские литералы






В языке С++ существуют литералы для разных встроенных типов (2.14 Literals):

123 // int

1.2 // double

1.2F // float

'a' // char

1ULL // unsigned long long

0xD0 // unsigned int в шестнадцатеричном формате

" as" // string

 

Однако в языке С++98 нельзя определить литералы для пользовательских типов. Это раздражает, а также нарушает принцип, что поддержка пользовательских и встроенных типов должна быть аналогичной. В частности, многие разработчики просили поддержку следующих литералов:

" Hi! " s // строка, но не “массив символов,

// оканчивающийся нулем”

1.2i // мнимое число

123.4567891234df // decimal floating point (IBM)

101010111000101b // двоичное число

123s // секунды

123.56km // не мили! (единицы измерения)

1234567890123456789012345678901234567890x // расширенная точность

 

С++11 поддерживает «пользовательские литералы» (user –defined literals) с помощью литеральных операторов (literal operators), которые задают соответствие литералов с определенным суффиксом для определенного пользовательского типа. Например:

// литерал для определения мнимого числа

constexpr complex< double> operator " " i(long double d)

{

return {0, d}; // complex – это тип литерала

}

// литерал дляstd:: string

std:: string operator" " s (const char* p, size_t n)

{

return string(p, n); // требуется динамическое выделение памяти

}

 

Обратите внимание на использование constexpr для вычисления выражения во время компиляции. При наличии указанных операторов, мы можем написать следующее:

template< class T> void f(const T&);

f(" Hello"); // передаем указатель на char*

f(" Hello" s); // передаем объект string (из 5 символов)

f(" Hello\n" s); // передаем объект string (из 6 символов)

auto z = 2+1i; // complex(2, 1)

 

Основная идея (реализации) этой возможности заключается в том, что после парсинга потенциального литерала, компилятор всегда проверяет суффикс. Механизм пользовательских литералов позволяет пользователю указать новый суффикс и что будет выполнено для литерала, расположенного до этого суффикса. Пользователь не может переопределить поведение встроенных литералов или расширить синтаксис литералов. Литеральный оператор может принимать значение в кавычках (в качестве строки) или без них.

Для использования литерала без кавычек достаточно определить оператор, принимающий единственный аргумент типа const char*:

Bignum operator" " x(const char* p)

{

Return Bignum(p);

}

Void f(Bignum);

F(1234567890123456789012345678901234567890x);

 

В operator”” x() передается С-строка вида " 1234567890123456789012345678901234567890". Обратите внимание, что мы не преобразуем явно это числовое значение в строку.

Пользовательские литералы можно определить для одного из четырех типов литералов:

· целочисленный литерал: литеральный оператор принимает единственный параметр типа unsigned long longили const char*.

· значение с плавающей точкой: литеральный оператор принимает единственный параметр типа long double или const char*.

· строковый литерал определяется литеральным оператором, принимающим пару аргументов (const char*, size_t).

· символьный литерал определяется литеральным оператором, принимающим единственный параметр типа char.

Обратите внимание, что вы не можете определить литеральный оператор для строкового литерала, принимающий только параметр типа const char* (без размера). Например:

// предупреждение: этот код будет работать не так, как вы ожидаете

string operator" " S(const char* p);

" one two" S; // ошибка: литеральный оператор не найден

 

Причина такого поведения заключается в том, что практически всегда, когда мы хотим определить «еще один тип строки» нам нужно знать количество символов.

Суффиксы должны быть короткими (например, s для строки, i для комплексных чисел, m для метров, x для расширенных целочисленных типов), что легко может приводить к коллизиям. Для предотвращения коллизий следует использовать пространства имен:

namespace Numerics {

//...

class Bignum { /*... */ };

namespace literals {

operator" " X(char const*);

}

}

using namespace Numerics:: literals;

 

См. также:

  • Standard 2.14.8 User-defined literals
  • [N2378==07-0238] Ian McIntosh, Michael Wong, Raymond Mak, Robert Klarer, Jens Mauer, Alisdair Meredith, Bjarne Stroustrup, David Vandevoorde: User-defined Literals (aka. Extensible Literals (revision 3)).

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.