C ++ OstReam挿入演算子がコンテキストを利用できるようにする必要があります
質問
私が取り組んでいるAPIについては、ユーザーがカスタムオブジェクトをに挿入できるようにしたい ostream
, 、しかし、これらのオブジェクトはそれ自体で意味がなく、メモリが制約されすぎて、コンテキストの追加のポインターまたは参照を含めるには拘束されています。 (メモリが限られている埋め込みシステムに数千万人の16-/32-/48ビットオブジェクトを考えてください。)
ユーザーが基礎となるコンテキストを初期化し、これらのオブジェクトのいずれかを調べるとします。
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をわずかに知っていますが、それがここで私を助けるかどうかはわかりません。
解決
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;
}
他のヒント
何時にアクセスできるか、何が変更され、何が変わるかを理解しているかどうかは完全にはわかりませんが、このようなことをすることができますか
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とは何ですか?
挿入演算子を使用している間にコンテキスト情報を渡す方法をファディングして見つけようとするのではなく、Cho Beobablueのような印刷方法のようなものを作成することをお勧めします。それは素晴らしくシンプルなソリューションであり、ファンシーなものはおそらくそれが価値があるよりも多くのトラブルです。
また、組み込みシステムにioStreamsを選択するのは奇妙です。それらは、C ++標準ライブラリの最も肥大化した部分の1つであり(実装だけでなく、設計による)、組み込みシステムで作業している場合は、これの代替案をロールすることもできます(それでも、 iOSTREAMSの基本設計)そして、おそらくiOSTREAMを効果的に、そして複数のスレッドで使用しようとするのと同じくらい迅速にそれを行うことができます。
私はこれが初めてなので、自分の答えを提供することで、ゲイリーとクレジットを共有することを妨げている場合、ゲイリーは、同じ参照を通して私がちょうど瞬間につまずいたことを指摘しました。 プライベート使用のためのストレージストレージ: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;
}