Невозможно использовать оператор<< с std::float128_t; как мне это распечатать?

У меня есть следующий код, который не компилируется с x86_64 GCC 13:

      #include <iostream>
#include <stdfloat>

int main() {
    std::cout << std::float128_t{1} << '\n';
}

Это дает мне следующую ошибку:

      <source>: In function 'int main()':
<source>:5:15: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'std::float128_t' {aka '_Float128'})
    5 |     std::cout << std::float128_t{1} << '\n';
      |     ~~~~~~~~~ ^~      ~~~~~~~~~~~~~
      |          |            |
      |          |            std::float128_t {aka _Float128}
      |          std::ostream {aka std::basic_ostream<char>}

Перечисленные неоднозначные перегрузки:

  • operator<<(long)
  • operator<<(unsigned long)
  • operator<<(bool)
  • ...

Как ни странно,operator<<(float)и другие типы с плавающей запятой не указаны.

Я проверил страницу поддержки компилятора для C++23, и эта функция должна поддерживаться:

См. страницу поддержки компилятора C++23.

Я что-то неправильно понимаю? Является ли cppreference неправильным, а расширенные типы с плавающей запятой еще не полностью поддерживаются? Как мне распечатать std::float128_tбез сторонних библиотек?

2 ответа

является необязательным

Ни одна из перегрузок расширенных типов с плавающей запятой из<stdfloat>гарантированно существуют. Ведь довольно часто это не так. На x86_64:

  • обычно представляет собой 80-битный тип с плавающей запятой и
  • представляет собой тип с плавающей запятой четырехкратной точности IEEE-754.

Это означает, что имеет более высокий ранг конверсии 1) , чем . Как результат,operator<<(std::float128_t)является необязательным:

В противном случае, если ранг преобразования с плавающей запятой расширенного типа с плавающей запятой меньше или равен рангу long double , преобразование форматирования происходит так, как если бы оно выполняло следующий фрагмент кода:

       bool failed = use_facet<num_put<charT, ostreambuf_iterator<charT, traits>>>(getloc()).put(*this, *this, fill(), static_cast<long double>(val)).failed();

В противном случае вызов операторной функции условно поддерживается семантикой, определяемой реализацией.

- [ostream.formatted]/[ostream.inserters.arithmetic] §5

GCC не обязан поддерживать его, и вам следует рассмотреть альтернативы печати расширенных типов с плавающей запятой.

Альтернативы

      #include <iostream>
#include <stdfloat>
#include <format>

int main() {
    std::cout << std::format("{}", std::float128_t{1}) << '\n';
}

Это решение в настоящее время работает и гарантированно будет работать. Расширенные типы с плавающей запятой реализованы с использованиемstd::to_chars, который необходим для поддержки всех арифметических типов.

      #include <print>
#include <stdfloat>

int main() {
    std::println("{}", std::float128_t{1});
}

Это решение пока не работает, поскольку libstdc++ не реализует<print>заголовок еще. Однако, как только это произойдет, это тоже сработает, потому чтоstd::printlnтакже используетstd::formatter.

Еслиstd::formatработает, почемуoperator<<не поддерживается?

В предложении содержится ответ на этот вопрос:

Операторы потоковой передачи используют виртуальные функцииnum_put<>::do_putиnum_get<>::do_getдля вывода и ввода арифметических типов. Для полной и правильной поддержки расширенных типов с плавающей запятой необходимо добавить новые виртуальные функции. Это был бы разрыв ABI. Хотя о прекращении ABI не может быть и речи, оно встретит сильную оппозицию. Это предложение не стоит усилий, которые потребуются, чтобы добиться прорыва ABI через комитет.

- P1467r9 §iostream


1) Ранг конверсии выше, потому чтоstd::float128_tможет представлять больше значений, чемlong double, см. [conf.rank] §2 .

Старым решением является libquadmath, который по умолчанию поставляется с GCC.

      #include <iostream>
#include <quadmath.h>

int main()
{
    __float128 x = 12.3; // `__float128` should be equivalent to `std::float128_t`.
    char buf[200];
    quadmath_snprintf(buf, sizeof buf, "%Qf", x);
    std::cout << buf << '\n';
}

Добавлять-lquadmathпри связывании.

Другие вопросы по тегам