2

C++ での演算子のオーバーロードで奇妙な動作が発生しています。クラスがあり、その内容が long double 以上かどうかを確認する必要があります。このチェックを行うために >= 演算子をオーバーロードしました。私の宣言は次のとおりです。

bool MyClass::operator>=(long double value) const;

私のクラスには、特定の条件下でのみ例外なく機能するキャストからロングダブルへの演算子もあると言わざるを得ません。ここで、この演算子を使用すると、コンパイラーは operator>= の使用があいまいであり、代替手段は次のとおりであると不平を言います。

  • 私の。
  • 組み込みのoperator>=(long double, int).

では、プログラムに演算子を強制的に使用させるにはどうすればよいでしょうか?

4

6 に答える 6

3

2015 更新:(double)objまたは、構文の代わりに構文を使用して変換機能を維持したい場合は、そのキーワードを前に付けてobj.to_double()変換関数を作成します。explicit変換をトリガーするには、明示的なキャストが必要です。個人的には、変換が toで.to_doubleない限り、構文が好きです.boolif(obj)explicitif(obj.to_bool())


変換演算子をドロップします。どこまでもトラブルの元になります。のような機能を持っています

to_double()

または、double 値を返し、その関数を明示的に呼び出して double を取得する同様のもの。

当面の問題については、次の問題があります。

obj >= 10

その表現を考えてみましょう。組み込み演算子は、変換演算子 long double() を使用して、型のユーザー定義変換シーケンスによって最初の引数と一致します。ただし、関数は、int から long double への標準変換シーケンス (整数から浮動小数点への変換) によって 2 番目の引数と一致します。2 つの引数の変換がある場合は常にあいまいですが、少なくとも 1 つの引数がより適切に変換され、残りの引数が 1 回の呼び出しでより悪く変換されることはありません。あなたの場合、組み込みのものは2番目の引数によく一致しますが、最初の引数には一致しませんが、関数は最初の引数によく一致しますが、2番目の引数には一致しません。

紛らわしいので、いくつか例を示します (char から int への変換はプロモーションと呼ばれ、char から int 以外への変換 (変換と呼ばれます) よりも優れています)。

void f(int, int);
void f(long, long);
f('a', 'a');

最初のバージョンを呼び出します。最初のすべての引数をより適切に変換できるためです。同様に、次の場合でも最初の呼び出しが行われます。

void f(int, long);
void f(long, long);
f('a', 'a');

最初の変換はより良く、2 番目の変換はより悪い変換ではないためです。しかし、以下はあいまいです:

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

この場合はもっと興味深いです。最初のバージョンは、完全一致によって最初の引数を受け入れます。2 番目のバージョンは、完全一致で 2 番目の引数を受け入れます。しかし、どちらのバージョンも、他の主張を少なくとも同じようには受け入れていません。最初のバージョンでは 2 番目の引数の変換が必要ですが、2 番目のバージョンでは引数の昇格が必要です。したがって、プロモーションはコンバージョンよりも優れていますが、2 番目のバージョンの呼び出しは失敗します。

上記のケースと非常によく似ています。標準の変換シーケンス (int/float/double から long double への変換) は、ユーザー定義の変換シーケンス (MyClass から long double への変換) よりも優れていますが、オペレーターのバージョンは選択されません。 ) は、組み込み演算子がその引数に必要とするものよりも悪い引数からの変換を必要とします (完全一致)。

オーバーロードの解決は C++ では複雑な問題であるため、その微妙なルールをすべて思い出すことは不可能です。しかし、大まかな計画を立てることはかなり可能です。お役に立てば幸いです。

于 2009-02-15T09:10:08.480 に答える
3

あなたが効果的に述べている a への暗黙的な変換を提供することによりdouble、私のクラスは a と同等にdoubleなりますdouble。あなた気にするなら、あなたのクラスは実際には a と「等価」ではなく、 への暗黙的な変換を提供するのではなく、明示的なGetAsDouble または ConvertToDouble メンバー関数doubleを提供することを検討する必要があります。double

現時点であいまいさがある理由は、がクラスのインスタンスでdouble である式のt >= d場合、コンパイラは常に左側または右側の変換を提供する必要があるため、式は実際にはあいまいです。sが呼び出されて s の組み込み演算子 >=が使用されるか、または d が a に昇格され、メンバー演算子 >= が使用されます。tdtoperator doubledoublelong double

編集、質問を更新して、変換が long double であり、比較が int に対するものであることを示唆しました。その場合、最後の段落は次のようになります。

現時点であいまいさがある理由は、がクラスのインスタンスであり、である式のt >= d場合、コンパイラは常に左辺または右辺のいずれかの変換を提供する必要があるため、式は実際には曖昧。'sが呼び出され、組み込み演算子 >= for andが使用されるか、または d が a に昇格され、メンバー演算子 >= が使用されます。tdinttoperator long doublelong doubleintlong double

于 2009-02-15T09:10:17.123 に答える
1

intではなくリテラルと比較していると思いますlong double

MyClass o;

if (o >= 42)
{
   // ...
}

その場合、両方の選択肢が同じくらい良い/複雑です。

あなたの使用operator long double()

  1. MyClass::operator long double()
  2. ビルトインoperator>=(long double, int)

あなたの使用MyClass::operator>=(long double)

  1. intへの組み込みの変換long double
  2. MyClass::operator>=(long double)
于 2009-02-15T09:12:05.293 に答える
0
  • 組み込み演算子>=(long double, int)。

あなたが定義したように見えます:

bool class::operator>=(long double value) { return value >= classValue; }

そして、あなたは行方不明です:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

そのため、コンパイラは変換する方法を決定できません。(あいまいです。)

おそらく、テンプレート化された関数 (またはメソッド) が役立つでしょうか?

a>=bがb >=aとは異なるメソッドを呼び出す状況に注意してください。

于 2009-02-15T16:10:04.023 に答える
0

あなたはlong double宣言を持っています。に変更してみてくださいdouble

于 2009-02-15T09:03:11.867 に答える
0

カスタム キャストと組み合わせて演算子のオーバーロードを使用すると、クラスのユーザーが非常に混乱する可能性があります。このクラスのユーザーは、それ自体が double に変換されること、または double と同等であることを期待するでしょうか? .greaterThan(double) 関数を使用しても、同じ目標を達成できますが、ユーザーを驚かせることはありませんか?

あいまいさを避けるために、比較する前に常にオブジェクトを明示的に double にキャストできると思います。しかし、もし私があなただったら、上記のアプローチを再考し、手の込んだ型キャストや演算子のオーバーロードではなく、直感的で驚くことのない方法で動作するコードを書くことに集中するでしょう。

(演算子のオーバーロードに関する FQA のすばらしい暴言に触発されました)

于 2009-02-15T09:09:09.857 に答える