Подтвердить что ты не робот

Почему я должен использовать long double для пользовательских литералов?

Следующий заданный пользователем литерал пропускает ошибку:

constexpr double operator "" _kg(double q)
{
   return q*1000;
}

но если добавлено long, ошибка исчезнет, ​​и код будет работать следующим образом:

constexpr double operator "" _kg(long double q)
{
   return q*1000;
}

ошибка:

‘constexpr double operator""_kg(double)’ has invalid argument list

Проблема вызвана только аргументом, а тип возврата может быть double без long.

Почему нужен long?

4b9b3361

Ответ 1

С++ 11 draft n3290 имеет это, чтобы сказать о параметрах, которые могут принимать пользовательские литералы (§13.5.8):

Объявление оператора literal должно иметь предложение-объявление-выражение, эквивалентное одному из следующих:

const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t

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

Ответ 2

Для литералов-операторов допускаются только следующие списки параметров:

  • (const char *) (1)
  • (unsigned long long int) (2)
  • (длинный двойной) (3)
  • (char) (4)
  • (wchar_t) (5)
  • (char16_t) (6)
  • (char32_t) (7)
  • (const char *, std:: size_t) (8)
  • (const wchar_t *, std:: size_t) (9)
  • (const char16_t *, std:: size_t) (10) (const char32_t *, std:: size_t) (11)

    • Буквенные операторы с этим списком параметров представляют собой необработанные литералы, используемые в качестве резервных копий для целочисленных и с плавающей запятой пользовательские литералы (см. выше)

    • Литеральные операторы с этими списками параметров являются оператором литерала первого выбора для пользовательских целых литералов

    • Литеральные операторы с этими списками параметров являются оператором литерала с первым выбором для пользовательских литералов с плавающей запятой

4-7. Буквенные операторы с этими списками параметров вызывается

пользовательские символьные литералы

8-11. Буквенные операторы с этими списками параметров вызывают пользовательские строковые литералы

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

Из справки cpp: http://en.cppreference.com/w/cpp/language/user_literal

Ответ 3

Stroustrup имеет отличный раздел о строковых литералах, где он заявляет (из спецификации):

  • литерал с плавающей запятой: принят оператором literal, принимающим один аргумент long double или const char *.

http://www.stroustrup.com/C++11FAQ.html#UD-literals

Ответ 4

Хотя отказ ANSI C определить форму объявления с переменными аргументами, которая может чисто обрабатывать тип long double с расширенной точностью, формат которого отличается от double, привел к тому, что тип, который фактически не рекомендуется на многих платформах (например, неудачный, IMHO, поскольку он был хорошим типом для использования не только на системах с сопроцессорами x87, но и на системах без FPU), единственным разумным способом для системы с надлежащими типами расширенной точности для обработки оператора типа:

long double a = 0.1;

должен иметь 0,1-ти минутный старт, как long double, равный 14,757,395,258,967,641,293/147,573,952,589,676,412,928; было бы абсурдно, чтобы этот оператор установил a в 7,205,759,403,792,794/72,057,594,037,927,936 (примерно 0,10000000000000000555, значение (double)0.1).

Вероятно, может быть несколько случаев, когда с начала числового литературного начала в качестве long double до преобразования с понижением может привести к тому, что он даст другое значение от того, что было бы, если бы он начал жизнь как double или float (например, ближайший float до 9007199791611905.0 равен 9007200328482816, что на 536870911 выше запрашиваемого значения, но (float)(double)9007199791611905.0 дает 9007199254740992, что ниже 536870913. Конечно, если требуется значение поплавка 9007200328482816.0f, вероятно, следует использовать десятичное представление, которое ближе к тому, что действительно нужно.