12

スティッキーになるように独自のカスタム ストリーム マニピュレータを実装するにはどうすればよいですか。たとえば、次のように整数をバイナリに変換したいとします。

cout << "decimal of 4: " <<  4 
     << "\ndecimal of 4: " << 4 
     << binary << "\nbinary of 4: " << 4 
     << "\nbinary of 4: " << 4 
     << nobinary << "\ndecimal of 4: " << 4 
     << "\ndecimal of 4: " << 4 << endl;

戻ります:

decimal of 4: 4
decimal of 4: 4
binary of 4: 100
binary of 4: 100
decimal of 4: 4
decimal of 4: 4
4

1 に答える 1

17

すべてを行うのは少し複雑です。わかりやすくするために、基本的なことから始めます。ユーザー定義の型にカスタムフォーマットフラグを使用することです。整数のカスタムフォーマットは以下のとおりです。

IOStreamクラスは[間接的に]派生し、そこからstd::ios_baseデータ用の2つのストアを提供します。それぞれsとsstd::ios_base::iword()です。で保存された割り当てられたメモリを維持することは簡単ではなく、幸いなことに、この比較的単純なユースケースでは必要ありません。対応する型への非参照を返すこれらの関数を使用するには、通常、プログラムで1回使用してインデックスを割り当て、カスタムフォーマットフラグにアクセスする必要があるときはいつでもそれを使用します。で、または最初に値にアクセスすると、ゼロで初期化されます。物事をまとめるために、これを示す小さなプログラムがあります:std::ios_base::pword()intvoid*std::ios_base::pword()conststd::ios_base::xalloc()iword()pword()

#include <iostream>

static int const index = std::ios_base::xalloc();

std::ostream& custom(std::ostream& stream) {
    stream.iword(index) = 1;
    return stream;
}

std::ostream& nocustom(std::ostream& stream) {
    stream.iword(index) = 0;
    return stream;
}

struct mytype {};
std::ostream& operator<< (std::ostream& out, mytype const&) {
    return out << "custom-flag=" << out.iword(index);
}

int main()
{
    std::cout << mytype() << '\n';
    std::cout << custom;
    std::cout << mytype()  << '\n';
    std::cout << nocustom;
    std::cout << mytype() << '\n';
}

現在、intlike4はユーザー定義型ではなく、これらに対して定義された出力演算子がすでに存在します。幸い、ファセットを使用して、より具体的にはを使用して、整数のフォーマット方法をカスタマイズできますstd::num_put<char>。さて、そうするためにあなたはいくつかのステップをする必要があります:

  1. 特殊な動作を与えるメンバーからクラスを派生させstd::num_put<char>、オーバーライドします。do_put()
  2. std::locale新しく作成したファセットを使用してオブジェクトを作成します。
  3. std::ios_base::imbue()新しいストリームstd::locale

std::localeユーザーにとってより良いものにするために、マニピュレーターを使用するときに適切なstd::num_put<char>ファセットを使用して新しいものを作成することをお勧めします。ただし、そうする前に、適切なファセットを作成することから始めましょう。

#include <bitset>
#include <iostream>
#include <limits>
#include <locale>

static int const index = std::ios_base::xalloc();

class num_put
    : public std::num_put<char>
{
protected:
    iter_type do_put(iter_type to,
                     std::ios_base& fmt,
                     char_type fill,
                     long v) const
    {
        if (!fmt.iword(index)) {
            return std::num_put<char>::do_put(to, fmt, fill, v);
        }
        else {
            std::bitset<std::numeric_limits<long>::digits> bits(v);
            size_t i(bits.size());
            while (1u < i && !bits[i - 1]) {
                --i;
            }
            for (; 0u < i; --i, ++to) {
                *to = bits[i - 1]? '1': '0';
            }
            return to;
        }
    }
#if 0
    // These might need to be added, too:
    iter_type do_put(iter_type, std::ios_base&, char_type,
                     long long) const;
    iter_type do_put(iter_type, std::ios_base&, char_type,
                     unsigned long) const;
    iter_type do_put(iter_type, std::ios_base&, char_type,
                     unsigned long long) const;
#endif
};

std::ostream& custom(std::ostream& stream) {
    stream.iword(index) = 1;
    return stream;
}

std::ostream& nocustom(std::ostream& stream) {
    stream.iword(index) = 0;
    return stream;
}

int main()
{
    std::locale loc(std::locale(), new num_put);
    std::cout.imbue(loc);
    std::cout << 13 << '\n';
    std::cout << custom;
    std::cout << 13  << '\n';
    std::cout << nocustom;
    std::cout << 13 << '\n';
}

少し醜いのはimbue()、習慣がマニピュレーターstd::localeを使用する必要があるということです。customこれを取り除くには、カスタムファセットが使用済みにインストールされていることを確認し、インストールされてstd::localeいない場合は、フラグを設定するときにインストールします。

std::ostream& custom(std::ostream& stream) {
    if (!stream.iword(index)
        && 0 == dynamic_cast<num_put const*>(
                &std::use_facet<std::num_put<char> >(stream.getloc()))) {
        stream.imbue(std::locale(stream.getloc(), new num_put));
    }
    stream.iword(index) = 1;
    return stream;
}

現在残っているのは、さまざまなタイプでdo_put()適切に機能するようにさまざまなメンバーをオーバーライドすることですが、これは演習として残されています。unsignedlong long

于 2012-11-11T21:25:30.837 に答える