6

だから私はC++で仮想ストリーミングインターフェースを持っています

class KxStream
{
public:
   virtual KxStream& operator<< ( u32 num ) = 0;
};

すべての組み込み型に対して多数の基本的な << 演算子があります。1つだけ挙げてみました。

次に、ストリーミング インターフェイスを実装するクラスをいくつか用意します。このような:

class KxCbuf : public KxStream
{
public:
   KxStream& operator<<( u32 num );
}

そのため、KxCbuf にはストリーミング インターフェイスの実装があります。ここまでは順調ですね。次に、ストリーム インターフェイスをオーバーロードするいくつかのクラスがあります。

class KxSymbol
{
   operator u32() const;
   friend KxStream& operator<<( KxStream& os, KxSymbol sym );
};

このクラスには組み込み型へのキャスト演算子があることに注意してください。これらのクラスの 1 つを、ストリーミング インターフェイスを実装するクラスの 1 つにストリーミングしようとすると、エラーが発生します。

KxCbuf buf;
KxSymbol sym;

buf << sym; // error!

コンパイラは、使用する関数について混乱します。Gcc は正常にコンパイルされますが、これを行う方法は複数あると言われています。MSVC は、複数のオーバーロードがあると言ってコンパイルしません。

src/variable.cpp(524) : error C2666: 'KxCbuf::operator <<' : 15 overloads have similar conversions

何が起こっているのかはわかっていますが、それを満足に解決する方法はわかりません。したがって、コンパイラは KxCbuf -> KxStream をキャストしてから、フレンド関数を呼び出すことができます。これは正しいことです。または、KxSymbol -> u32 をキャストし、KxStream から継承された KxCbuf で u32 << 演算子を呼び出すことができます。

私はそれを2つの(悪い)方法で解決できます。

明確なものでストリーミングすることから始めることができます。

buf << "" << sym;

このように、"" の最初のストリーム演算子の戻り値は KxStream を返し、すべて問題ありません。または、実装クラスに冗長なストリーム演算子を実装できます。たとえば、以下を KxSymbol に追加できます。

friend KxStream& operator<<( KxCbuf& os, KxSymbol sym );

最初の答えは常に機能しますが、確かに醜いです。2 番目の答えも、冗長なストリーム オペレーターを作成する必要があり、新しいストリーム オペレーターを定義する必要がある場所で KxStream の実装が常に表示されるとは限らないという点で、醜いものです。

理想的には、KxStream インターフェイスの実装が KxStream オブジェクトのように機能し、あいまいな変換を引き起こす暗黙のキャストを回避したいと考えています。

これを解決するにはどうすればよいですか?

(ps。ライブラリのカスタムシリアライゼーションスキーム用に独自のストリーミングオペレーターを作成する必要があります。独自のシリアライゼーションクラスを持つブーストまたは同様のサードパーティライブラリを使用できません)

@Edit: KxSymbol -> u32 への変換など、コンパイラによる暗黙的な変換の使用を制御することに関連するいくつかの良い答えがありますが、残念ながら暗黙的な変換はコードにとって重要です。たとえば、KxSymbol は、文字列をテーブルに格納し、それらを数値として返すクラスで、文字列を数値として比較できるようにします。たとえば、2 つの記号が等しくない場合、文字列は同じではありません。また、一部のデータ構造ではシンボルを数値として格納します。

これを反対側から解決する方法はありますか?どうにかして、KxStream の実装を他の暗黙のキャストよりも優先して KxStream オブジェクトにキャストする必要があることをコンパイラに理解させますか?

たとえば、組み込み型に operator<< を使用する前に、まず KxCbuf を KxStream にキャストするようにコンパイラに強制するとどうなるでしょうか。これにより、KxStream よりもオーバーロード operator<< が常に優先されます。- オーバーロードには 1 つのキャストが必要で、KxStream には 2 つのキャストが必要です。

4

3 に答える 3

5

C++11 コンパイラを使用している場合は、変換関数を「明示的」とマークします。そうすれば、u32 への暗黙的な変換が行われず、この種のあいまいさがなくなります。

于 2012-08-13T15:05:46.583 に答える
3

最も簡単で安全な方法は、暗黙的な変換を からoperator u32() const;名前付きメソッドに変更することu32 as_u32() constです。これはあいまいさを取り除くだけでなく、将来トラブルに巻き込まれるあらゆる種類の望ましくない偶発的な変換を防ぐことができます.

于 2012-08-13T15:07:40.090 に答える
0

私は答えがあるかもしれないと思います。組み込みのストリーム演算子を仮想プライベートメソッドに実装します。

だから私はこのようなことをします:

class KxStream
{
public:
   KxStream& operator<< ( u32 num ) { return stream_i( num ); }
private:
   virtual KxStream& stream_i ( u32 num ) = 0;
};

class KxCbuf : public KxStream
{
private:
   KxStream& stream_i( u32 num );
}

現在、コンパイラがKxCbufを介して組み込み演算子<<を呼び出す方法はありません。KxStreamのパブリックメソッドのみを使用できます。しかし、私はまだプライベートstream_iメソッドを介して仮想メソッドのオーバーロードを取得します。したがって、KxCbufにストリーミングする場合、コンパイラは常にKxStreamにキャストする必要があります。その唯一の方法。

フレンドオーバーロードとビルトインのどちらを使用するかを決定する場合、ビルトインには2つのキャストが必要であり、オーバーロードには1つのキャストが必要なため、フレンドオーバーロードが優先されます。

于 2012-08-13T16:52:15.477 に答える