7

私はこのクラスを持っています:

class MyClass {

    public:

        int operator[](const std::string&);
        const std::string& operator[](const int&) const;

    ...
};

ただし、constリテラル0を使用して2番目の演算子を呼び出すと、非常に機能します。

MyClass myclass;
std::cout << myclass[0] << std::endl;

このエラーが発生しました:

In function 'int main()':
ambiguous overload for 'operator[]' in 'myclass[0]'
note: candidates are:
note: const int MyClass::operator[](const string&)|
note: const string& MyClass::operator[](const int&) const

私は状況が何であるかを理解していると思います (0 は文字列または整数のいずれかになりますか?)、しかし私の質問は: これを解決し、演算子のオーバーロードを維持する方法はありますか?

4

3 に答える 3

7

呼び出しMyClass::operator[](const std::string&)には、次の変換が含まれます。

myclassからMyClass&までMyClass&: パーフェクト マッチ

0intto const char*to std::string: ユーザー定義の変換

呼び出しMyClass::operator[](const int&) constには、次の変換が含まれます。

myclassから: MyClass&constconst MyClass&修飾

0からintまでint: パーフェクト マッチ

このような状況では、引数 X に対して 1 つのオーバーロードが "優れている" が、引数 Y に対しては別のオーバーロードが "優れている" 場合、どちらのオーバーロードも最適なオーバーロードとは見なされず、コンパイラは文句を言う必要があります (両方に勝る 3 つ目のオーバーロードはないと仮定します)。 .

const2 つのオーバーロードを両方または両方に変更することは可能non-constですか? そうでない場合は、この種の状況を処理するために 3 番目のオーバーロードを追加できます。

const std::string& operator[](int n) {
    return static_cast<const MyClass&>(*this)[n];
}
于 2012-12-20T19:54:40.580 に答える
4

0にすることはできませんが、暗黙的に に変換stringできることを意味するポインタにすることができます。これは、またはのような他の定数積分には当てはまらないことに注意してください--具体的には。string1420

4.10 ポインタ変換

1/null ポインター定数は、0 に評価される整数型の整数定数式 (5.19) の右辺値です。null ポインター定数はポインター型に変換できます。結果はその型の null ポインター値であり、オブジェクトへのポインターまたは関数型へのポインターの他のすべての値と区別できます。同じ型の 2 つのヌル ポインター値は、比較すると等しくなります。null ポインター定数から cv 修飾型へのポインターへの変換は単一の変換であり、ポインター変換とそれに続く修飾変換 (4.4) のシーケンスではありません。

したがって、 の場合、 myclass[0]、または ` null ポインター定数0のいずれかになります。int

標準では、ポインターを受け取るstd::stringexplicitコンストラクターがあることも規定されています。char

size_type find_last_not_of (const charT* s, size_type pos = npos) const;

これで、operator&メソッドは両方とも参照型のパラメーターを受け取るためconst、一時的に渡すことができます。これが、コンパイラーが混乱する理由です。コンパイラーはint、どちらが必要なのかわかりません。stringstring(const char*)

この問題を解決する方法については、一歩後退します。operator[]あなたの2つの機能は明らかに異なることをしているように私には思えます。または、異なる入力が与えられても、同じことを行う可能性があります。それらが異なることを行う場合は、異なる (適切な) 名前を持つメンバー関数を提供し、operator[]構文の使用をスキップします。おそらく、これらのメソッドの 1 つは、実際にインデックス付けされたものを返します。その場合、そのメソッドのoperator[]構文を使用しますが、その構文だけを使用します。

それらが実際に同じことを行い、それが index によってアイテムを返すことである場合、私はこれに対して 1 つのメソッドのみを提供し、それが by 値を取るようにsize_tします。string次に、たとえば aから aに変換する何らかの種類の変換関数 (できれば、フリーの非メンバー関数の形式) を提供することもできますsize_t。これを行うと、次のようにインデックスを作成するときにコードを記述できますstring

myPos[str_to_index(str)];
于 2012-12-20T19:55:44.963 に答える
3

リテラル0は特別です。8 進定数であるだけでなく、任意のポインター型の null ポインターに変換することもできます。これにより、 の-constructorが0実行可能になります。char const *std::string

どちらのオーバーロードも優れていない理由は、演算子の int オーバーロードにconstインスタンス CV 修飾子があるためです。そうすれば、両方のオーバーロードが変換を必要とし、同じように悪いことになります。

明らかな回避策は、const オーバーロードが必要であることを明示することです。

static_cast<MyClass const &>(myclass)[0]
于 2012-12-20T19:47:16.470 に答える