【问题标题】:C++ Custom I/O manipulator for hexadecimal integers用于十六进制整数的 C++ 自定义 I/O 操纵器
【发布时间】:2016-03-11 16:37:31
【问题描述】:

我正在尝试用 C++ 编写一个自定义 I/O 操纵器,它可以根据提供的大小以0xFFFF 的形式编写格式良好的十六进制整数。

例如:

  • char c = 1 变为 0x01
  • short s = 1 变为 0x0001

等等。 在我的代码中找不到错误,即打印垃圾:

#include <iostream>
#include <iomanip>


class hexa_s
{
   mutable std::ostream *_out;

   template<typename T>
   const hexa_s& operator << (const T & data) const
   {
       *_out << std::internal << std::setfill( '0' ) << std::hex << std::showbase << std::setw( sizeof( T ) * 2 ) << data;

       return *this;
   }

   friend const hexa_s& operator <<( std::ostream& out, const hexa_s& b )
   {
       b._out = &out;
       return b;
   }
};

hexa_s hexa( )
{
    return hexa_s( );
}


int main()
{
    int value = 4;

    std::cout << hexa << value << std::endl;

    return 0;
}

【问题讨论】:

  • 它应该是sizeof(T) * CHAR_BIT / 4,或者更好的是std::numeric_limits&lt;T&gt;::digits() / 4(也许有适当的四舍五入)。

标签: c++ hex iostream iomanip


【解决方案1】:

这一行

std::cout << hexa << value << std::endl;

写入一个指针(指向函数 hexa)。应该调用该函数。

【讨论】:

  • 这肯定是错误之一,谢谢,但看起来它不是唯一的。看起来现在它无法在hexa() &lt;&lt; value 之后流式传输std::endl
  • friend const hexa_s&amp; operator &lt;&lt;( std::ostream&amp; out, const hexa_s&amp; b ) 应该返回对std::ostream 的引用,而不是对hexa_s 的引用
【解决方案2】:

这绝不是批评。在我看来,写一个 io 操纵器并不是一件小事。有很多“假设”和“陷阱”。

我可能会选择这样做。你怎么看?

#include <iostream>
#include <utility>
#include <limits>
#include <iomanip>


// in the general case, return a value unchanged
template<class Integral> auto as_integer(Integral i) { return i; }

// but in the case of chars, we must convert them to integers
// otherwise operator<< treats them as characters and does not
// obey the hex iomanipulator
auto as_integer(char c) { return int(c) & 0xff; }
auto as_integer(unsigned char c) { return unsigned(c) & 0xff; }

// This is a basic hex printer for any integral
template<typename Integral>
struct hex_printer
{
    static constexpr size_t hex_digits = sizeof(Integral) * 2;

    hex_printer(Integral i) : _i(i) {}

    std::ostream& operator()(std::ostream& os) const
    {
        auto flags = os.flags();
        try {
            os << std::setfill('0') << std::setw(hex_digits) << std::hex << as_integer(_i);
        }
        catch(...) {
            os.flags(flags);
            throw;
        }
        os.flags(flags);
        return os;
    }

    Integral _i;
};


template<typename Integral>
inline std::ostream& operator<<(std::ostream& os, hex_printer<Integral> const& hp)
{
    return hp(os);
}

template<typename Integral>
auto neat_hex(Integral i) {
    return hex_printer<std::decay_t<Integral>>(i);
}

int main()
{
    int x= 0xf045;
    short y = 0x6fa;
    std::int64_t z = 0xe32;
    std::uint8_t w = 0xde;

    using namespace std;
    cout << neat_hex(x) << " " << neat_hex(y) << " " << neat_hex(z) << " " << neat_hex(w) << endl;
    return 0;
}

示例输出:

0000f045 06fa 0000000000000e32 de

【讨论】:

  • 我同意,这不是一项小工作。关于您的代码,对我来说它不适用于std::int8_t。另一件小事,你认为有可能让它像其他 std &lt;iomanip&gt; 没有 operator() 而只是使用像 std::cout &lt;&lt; neat_hex &lt;&lt; value &lt;&lt; std::endl 这样的流式运营商一样工作吗?
  • Uint8 是一个字符,所以发出一个字符。您需要为 Uint8 提供一个特化,在函数对象中流式传输之前将其转换为 int
  • 这可能是可能的,但非常困难。您无法预测机械手右侧会出现什么
  • 我修改了代码,现在我总是转换为Integralstd::hex &lt;&lt; Integral(_i);,但它仍然不适用于std::int8_t。不幸的是,它仍然被视为char。如果我将其转换为int,而不是将255 打印为FFFFFFFF,我不能说为什么。
  • 你需要将 Uint8 转换成更大的东西。 Uint8 和 int8 上的运算符
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
  • 2012-01-29
  • 2016-02-24
  • 2010-10-06
  • 2011-04-26
  • 1970-01-01
相关资源
最近更新 更多