1

私が取り組んでいるAPIの場合、ユーザーがカスタムオブジェクトをに挿入できるようにしたいのですostreamが、これらのオブジェクトはそれ自体では意味がなく、メモリに制約があり、コンテキストの追加のポインターや参照を含めることができません。(メモリが限られている組み込みシステムでは、数千万の16- / 32- / 48ビットオブジェクトを考えてみてください。)

ユーザーが基になるコンテキストを初期化し、次のオブジェクトの1つを検索するとします。

DDB ddb("xc5vlx330t");
Tilewire tw = ddb.lookUpTilewire("DSP_X34Y0", "DSP_IMUX_B5_3");
...
std::cout << complexDataStructure;

まったく異なるスコープで、おそらくユーザーの明示的なコードから遠く離れてネストされている場合は、オブジェクトをに挿入する必要がありますが、ostream使用ddbできません。

os << tw;

twによってカプセル化された実際の値はです97,594,974が、必要な出力は次のとおりです。

DSP_IMUX_B5_3@[263,84] DSP "DSP_X34Y0" (1488@77406)

これが機能するためには、適切な挿入演算子がにアクセスする必要がありますがddb、静的またはグローバル変数または関数に依存することはできません(マルチスレッドの理由により)。私がやりたいは、ユーザーが次のようなストリームラッパーを要求して使用できるようにすることです。

ostream& wrappedCout = ddb.getWrappedOstream(std::cout);

返されるostreamのサブクラスには、それを必要とする特別なストリームインサーターが使用するddbへの参照と、std::coutすべての出力を転送する元のストリーム(この場合)への参照が含まれます。

残念ながら、私が思いついた継承または構成スキームは、コード化するのが面倒であり(大きな懸念ではありません)、ユーザーにとって問題になる可能性があります(はるかに大きな懸念)。挿入演算子でddbをエレガントに利用できるようにする方法に関する提案はありますか?私はboost.Iostreamsをわずかに認識していますが、それがここで私を助けるかどうかはわかりません。

4

4 に答える 4

1

iword/pwordメカニズムを使用してddbへの参照を格納するカスタムストリームマニピュレーターを記述します。次に例を示します。マルチスレッドプログラムでiwork_indexesマップの周りにロックを追加する必要があります。

class dbb
{
public:
    explicit dbb(int value) : m_value(value) {}
    int value() const { return m_value; }
private:
    int m_value;
};

class dbb_reliant_type
{
public:
    dbb_reliant_type(const std::string& value) : m_value(value) {}
    const std::string& value() const { return m_value; }
private:
    std::string m_value;
};

typedef std::map<std::ostream*, int> iword_map;
iword_map iword_indexes;

inline int get_iword_index(std::ostream& os)
{
    iword_map::const_iterator index = iword_indexes.find(&os);

    if(index == iword_indexes.end())
    {
        std::pair<iword_map::iterator, bool> inserted = iword_indexes.insert(std::make_pair(&os, os.xalloc()));
        index = inserted.first;
    }

    return index->second;
}


inline std::ostream& operator<<(std::ostream& os, const dbb& value)
{
    const int index = get_iword_index(os);

    if(os.pword(index) == 0)
        os.pword(index) = &const_cast<dbb&>(value);

    return os;
}

std::ostream& operator<<(std::ostream& os, const dbb_reliant_type& value)
{
    const int index = get_iword_index(os);
    dbb* deebeebee = reinterpret_cast<dbb*>(os.pword(index));
    os << value.value() << "(" << deebeebee->value() << ")";
    return os;
}

int main(int, char**)
{
    dbb deebeebee(5);
    dbb_reliant_type variable("blah");
    std::cout << deebeebee << variable << std::endl;
    return 0;
}
于 2010-06-24T23:00:57.523 に答える
1

何にいつアクセスできるのか、何を変更できるのか、何を変更できないのか、よくわかりませんが、こういうことはできますか?

struct TilewireFormatter {
    DDB *ddb;
    TilewireFormatter(DDB* d) : ddb(d) {}

    print(std::ostream& out, const Tilewire& obj) {
        // some formatting dependent on ddb
        out << obj;
    }
};

out << tw;と置き換えformatter.print(out, tw)ます;

次に、Tilewireに<<演算子のオーバーロードを提供せず、ddbが何であるかに基づいてフォーマットするために使用されるTilewireFormatterのインスタンスを渡しますか?

于 2010-06-24T23:02:08.660 に答える
0

挿入演算子を使用している間にコンテキスト情報を渡す方法を見つけようとするのではなく、choobablue が提案するような print メソッドのようなものを作成することをお勧めします。これは素晴らしくシンプルなソリューションであり、手の込んだものはおそらく価値があるよりも面倒です.

また、組み込みシステムに iostream を選択するのも奇妙だと思います。それらは C++ 標準ライブラリの最も肥大化した部分の 1 つであり (実装だけでなく、設計によっても)、組み込みシステムで作業している場合は、これの独自の代替手段を展開することもできます (まだに基づいています)。 iostream の基本的な設計) であり、おそらく iostream を複数のスレッドで効果的に使用しようとするのと同じくらい迅速に行うことができます。

于 2010-06-24T23:14:55.763 に答える
0

私はこれに慣れていないので、私自身の回答を提供することが Gary とクレジットを共有するのを邪魔する場合に備えて、Gary は同じ参照を通じて、私が少し前に偶然見つけたものを指摘しました: 私的使用のためのストリーム ストレージ: iword、pword、および xalloc

#include <iostream>

// statically request a storage spot that can be associated with any stream
const int iosDdbIndex = std::ios_base::xalloc();

class DDB {
public:
    // give the stream a pointer to ourselves
    void bless(std::ostream& os) { os.pword(iosDdbIndex) = this; }
    // provide a function that the insertion operator can access
    int getSomething(void) { return 50; }
};

class Tilewire {
    friend std::ostream& operator<< (std::ostream& os, Tilewire tilewire);
    // encapsulate a dummy value
    int m;
public:
    // construct the Tilewire
    Tilewire(int m) : m(m) {}
};

std::ostream& operator<< (std::ostream& os, Tilewire tilewire) {
    // look up the pointer to the DDB object
    DDB* ddbPtr = (DDB*) os.pword(iosDdbIndex);
    // insert normally, and prove that we can access the DDB object's methods
    return os << "Tilewire(" << tilewire.m << ") with DDB param " << ddbPtr->getSomething();
}

int main (int argc, char * const argv[]) {
    DDB ddb;
    ddb.bless(std::cout);
    std::cout << Tilewire(0) << std::endl;
    return 0;
}
于 2010-06-25T01:17:43.233 に答える