6

以下はテストコードです。

struct A
{
  operator int ();
  operator int () const;
};

void foo (const int);

今、呼び出すと:

foo(A());  // calls A::operator int()

常に非 const バージョンを選択するのはなぜですか? 作成operator const int () const;しても、呼び出しには影響しませんfoo()。標準的な参考文献とは別に、誰かがその背後にある理由を論理的に説明できますか?

4

3 に答える 3

13

A()Aconst 修飾されていない一時オブジェクトを提供します。式は右辺値式です、はい、しかしそれはオブジェクトを const 修飾A()しません。A

Aオブジェクトは const 修飾されていないため、非 constはoperator int()完全一致であり、constoperator int()は修飾変換を必要とするため、非 const オーバーロードが最適な一致として選択されます。

const 修飾したい場合は、const-qualified を明示的に要求する必要がありますA

foo(identity<const A>::type());

は次のようにidentity定義されます

template <typename T>
struct identity { typedef T type; };

operator const int() constと の間には実際には違いがないことに注意してくださいoperator int() const: 結果は右辺値であり、クラス型の右辺値のみを const 修飾できます (intはクラス型ではありません)。

void foo(const int)あなたが持っている との間に違いはないことにも注意してくださいvoid foo(int)。パラメータ型の最上位の const 修飾子は、関数の型に影響しません (つまり、これらの宣言の両方の型は ですvoid foo(int))。他の理由の中でも特に、これは最上位の const 修飾子があるかどうかが呼び出し元にとって重要ではないためです。とにかくコピーを作成する必要があります。最上位の const 修飾子は、関数の定義のみに影響します。

于 2011-06-29T03:22:54.993 に答える
5

James McNellisの答えは本当にすべてをカバーしていましたが、より多くの説明があっても問題はありません (願っています)。

そう。

電話すると…

    o.operator int()

…その場合、オーバーロードの選択はの constness にo完全に依存します。

他には何もありません。

理由を確認するには、次のクラスを検討してください。

struct Bar
{
    void f() {}
    void f() const {}
};

技術的には、これらのメンバー関数はメンバー関数である必要はありません。それらは、独立した機能として選択された可能性もあります。しかし、彼らはBar引数を必要とします:

struct Bar
{};

void f( Bar& ) {}
void f( Bar const& ) {}

そしてうまくいけば、あなたがそうするとき、それがより簡単にわかるようになりました

Bar o;
f( o );

最初の機能を選択できます。そしてそうです。2 番目の関数が選択された場合、最初の関数を取得できないためです。オブジェクトを にすると、最初のオブジェクトを選択すると正確さが失われるためですconstconstそのため、オブジェクトが 2 番目のオブジェクトconstのみを選択できるため、そうでない場合はconst1 番目のオブジェクトが選択されます。

要するに、このルールに代わる唯一の実際的な方法は、常に 2 番目のルールを選択することです。

乾杯 & hth.,

于 2011-06-29T03:59:19.950 に答える
4

C++ について覚えておかなければならないルールの 1 つは、オーバーロードを選択するときに返される値が考慮されないことです。この場合、operator int関数はパラメーターをとらないため、パラメーター リストを使用して選択肢を絞り込むこともできません。呼び出し元のオブジェクトの constness だけを使用できます。これは新しい一時オブジェクトであるため、const ではないため、const オーバーロードを選択しません。

于 2011-06-29T03:32:52.783 に答える