αλε*_*λυτ 15 c++ binary language-lawyer c++14
C++ 14通过0b
为值键入prefix来增加使用二进制文字的能力:
int v = 0b1111; // 15 in decimal
Run Code Online (Sandbox Code Playgroud)
但是没有std::bin
类似std::hex
或者流的操纵器std::oct
.所以我需要std::bitset
用于打印目的:
std::cout << std::bitset<4>(v) << "\n";
Run Code Online (Sandbox Code Playgroud)
是否已提出或考虑过?如果是这样,这个想法的现状是什么?
据我所知,没有提交添加格式标志的提案来添加二进制格式和/或操纵器std::bin
.您可以访问http://www.open-std.org/jtc1/sc22/wg21/docs/papers/查看提案.我很确定添加二进制文字的提议没有添加这个功能(快速搜索显示N3472,但我不确定这是否是本文的最新版本).
从技术角度来看,添加可能并不容易!各种标志通常都存储在流类中的一个字中,并且有各种原因用尽所有位.现有的三个设置(std::ios_base::oct
,std::ios_base::dec
,std::ios_base::hex
)能很好地被存储在只是2个比特.当然,这三个值将使一个值保持打开,除了该值通常用于默认设置,即在读取时不修复基数.结果,可能有必要改变流类的布局或使处理效率降低(例如,通过某种方式使用iword()
存储二进制格式化的附加可能性).我还没有分析是否存在任何实现的实际问题(我知道我的实现没有,但如果我没记错的话,我确实使用了一个单词中的所有位).
如果要支持二进制格式化,通过自定义std::num_put<char>
构面添加相对容易.下面是一个简单的例子.它不处理一些可能需要的格式化选项,如填充或数字分隔符:
#include <iostream>
#include <limits>
#include <locale>
class binary_num_put
: public std::num_put<char> {
template <typename T>
iter_type common_put(iter_type out, std::ios_base& str, char_type fill,
T original, unsigned long long v) const {
if (str.flags() & std::ios_base::basefield) {
return this->std::num_put<char>::do_put(out, str, fill, original);
}
if (str.flags() & std::ios_base::showbase) {
*out++ = '0';
*out++ = str.flags() & std::ios_base::uppercase? 'B': 'b';
}
unsigned long long mask(1ull << (std::numeric_limits<unsigned long long>::digits - 1));
while (mask && !(mask & v)) {
mask >>= 1;
}
if (mask) {
for (; mask; mask >>= 1) {
*out++ = v & mask? '1': '0';
}
}
else {
*out++ = '0';
}
return out;
}
iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long v) const {
return common_put(out, str, fill, v, static_cast<unsigned long>(v));
}
iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long long v) const {
return common_put(out, str, fill, v, static_cast<unsigned long long>(v));
}
iter_type do_put(iter_type out, std::ios_base& str, char_type fill, unsigned long v) const {
return common_put(out, str, fill, v, v);
}
iter_type do_put(iter_type out, std::ios_base& str, char_type fill, unsigned long long v) const {
return common_put(out, str, fill, v, v);
}
};
std::ostream& bin(std::ostream& out) {
auto const& facet = std::use_facet<std::num_get<char>>(out.getloc());
if (!dynamic_cast<binary_num_put const*>(&facet)) {
std::locale loc(std::locale(), new binary_num_put);
out.imbue(loc);
}
out.setf(std::ios_base::fmtflags(), std::ios_base::basefield);
return out;
}
int main()
{
std::cout << std::showbase << bin << 12345 << " "
<< std::dec << 12345 << "\n";
}
Run Code Online (Sandbox Code Playgroud)