Невозможно использовать оператор<< с 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 через комитет.
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
при связывании.