提问人:Jan Schultke 提问时间:6/18/2023 更新时间:6/18/2023 访问量:716
不能使用运算符<< 和 std::float128_t;如何打印?
Can't use operator<< with std::float128_t; how do I print it?
问:
我有以下代码,它不能使用 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 特性 | 论文 | libstdc++ | libc++ | MVSV STL |
---|---|---|---|---|
扩展浮点类型的标准名称和库 支持 |
P1467R9 | 13 | 19.37** |
请参阅 C++23 编译器支持页面
我是不是误解了什么?cppreference 是否错误,并且尚未完全支持扩展浮点类型?如何在没有第三方库的情况下打印 std::float128_t
?
答:
operator<<(std::float128_t)
是可选的
不能保证存在任何扩展浮点类型的重载。因为事实并非如此,这是很常见的。
在x86_64:operator<<
<stdfloat>
std::float128_t
long double
通常是 80 位浮点类型,并且std::float128_t
是四精度 IEEE-754 浮点类型。
这意味着1) 的转换排名大于 。
因此,是可选的:std::float128_t
long double
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 来支持它,您应该考虑打印扩展浮点类型的替代方法。operator<<
选择
#include <iostream>
#include <stdfloat>
#include <format>
int main() {
std::cout << std::format("{}", std::float128_t{1}) << '\n';
}
此解决方案目前有效,并保证有效。
扩展浮点类型是使用 实现的,这是支持所有算术类型所必需的。std::formatter
std::to_chars
#include <print>
#include <stdfloat>
int main() {
std::println("{}", std::float128_t{1});
}
此解决方案尚不起作用,因为 libstdc++ 尚未实现标头。
但是,一旦这样做,这也将起作用,因为还使用 .<print>
std::println
std::formatter
如果有效,为什么不支持?std::format
operator<<
提案文件回答了这个问题:
流式处理运算符使用虚函数,用于算术类型的输出和输入。为了完全正确地支持扩展浮点类型,需要添加新的虚拟函数。这将是 ABI 中断。虽然 ABI 突破并非不可能,但它会遭到强烈反对。该提案不值得为使 ABI 突破委员会而付出必要的努力。
num_put<>::do_put
num_get<>::do_get
1) 转化排名更大,因为可以表示比 更多的值,参见 [conv.rank] §2。std::float128_t
long double
老式的解决方案是 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
评论
__float128
并具有相同的表示形式,但它们是不同的类型。 记录为 convert ,因此在使用它时可能需要强制转换 to 以避免收到编译器警告或更糟的情况。std::float128_t/_Float128
quadmath_snprintf
__float128
std::float128_t
__float128
std::is_same_v
__float128
_Float128
-Wall -Wextra
_Float128
_Float128
__float128
static_assert(std::numeric_limits<__float128>::is_iec559);
printf
quadmath.h
_Float128
评论