@FredOverflow に基づいて再発明したバージョンを投稿したいと思います。以下の修正を行いました。
修理:
- の右側は参照型である
operator<<
必要があります。const
@FredOverflow のコードでは、驚くべきことに標準ライブラリと互換性のないh.x >>= 4
output を変更し、型はコピー構築可能である必要があります。h
T
- のみ
CHAR_BITS
が 4 の倍数であると仮定します。@FredOverflow のコードは 8 ビットであると仮定しますが、これは常に正しいとは限りません。DSP の一部の実装では、特に、 16 ビット、24 ビット、32 ビットなどはchar
珍しくありません。 char
.
向上:
- 整数型で利用可能な他のすべての標準ライブラリ マニピュレータをサポートします
std::uppercase
。ではフォーマット出力が使用されるため_print_byte
、標準ライブラリ マニピュレータは引き続き使用できます。
- 個別のバイトを出力するために追加
hex_sep
します (C/C++ では、「バイト」は定義上、サイズが の記憶単位であることに注意してくださいchar
)。テンプレート パラメーターを追加し、それぞれSep
インスタンス化_Hex<T, false>
します。_Hex<T, true>
hex
hex_sep
- バイナリ コードの肥大化を回避します。関数は、異なる のインスタンス化を避けるために、関数パラメータ
_print_byte
を使用して から抽出されます。operator<<
size
Size
バイナリ コードの肥大化の詳細:
hex
改善点 3 で述べたように、 とがどれほど広くhex_sep
使用されていても、(ほぼ) 重複した関数の 2 つのコピーのみがバイナリ コードで存在します:_print_byte<true>
と_print_byte<false>
. そして、この重複はまったく同じアプローチを使用して排除できることにも気付いたかもしれません: 関数パラメーターを追加しますsep
。はい。ただし、その場合はランタイムif(sep)
が必要です。プログラムで広範囲に使用できる共通のライブラリ ユーティリティが必要なので、実行時のオーバーヘッドではなく重複を妥協しました。私はコンパイル時を使用してこれを達成しましたif
:C++ 11 std::conditional
、関数呼び出しのオーバーヘッドは、うまくいけばinline
.
hex_print.h:
namespace Hex
{
typedef unsigned char Byte;
template <typename T, bool Sep> struct _Hex
{
_Hex(const T& t) : val(t)
{}
const T& val;
};
template <typename T, bool Sep>
std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h);
}
template <typename T> Hex::_Hex<T, false> hex(const T& x)
{ return Hex::_Hex<T, false>(x); }
template <typename T> Hex::_Hex<T, true> hex_sep(const T& x)
{ return Hex::_Hex<T, true>(x); }
#include "misc.tcc"
hex_print.tcc:
namespace Hex
{
struct Put_space {
static inline void run(std::ostream& os) { os << ' '; }
};
struct No_op {
static inline void run(std::ostream& os) {}
};
#if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here
#error "hex print utility need CHAR_BIT to be a multiple of 4"
#endif
static const size_t width = CHAR_BIT >> 2;
template <bool Sep>
std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size)
{
using namespace std;
auto pbyte = reinterpret_cast<const Byte*>(ptr);
os << hex << setfill('0');
for (int i = size; --i >= 0; )
{
os << setw(width) << static_cast<short>(pbyte[i]);
conditional<Sep, Put_space, No_op>::type::run(os);
}
return os << setfill(' ') << dec;
}
template <typename T, bool Sep>
inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h)
{
return _print_byte<Sep>(os, &h.val, sizeof(T));
}
}
テスト:
struct { int x; } output = {0xdeadbeef};
cout << hex_sep(output) << std::uppercase << hex(output) << endl;
出力:
de ad be ef DEADBEEF