2

次のクラスを検討してください。

class Test
{
public:
    Test( char );
    Test( int );
    operator const char*();
    int operator[]( unsigned int );
};

私がそれを使用するとき:

Test t;
Test& t2 = t[0];

どの operator[] を使用するかを判断できないというコンパイラ エラーが発生します。MSVC と Gcc の両方。さまざまなエラー。しかし、同じ問題。

私は何が起こっているのか知っています。int または char のいずれかから Test を構築でき、Test::operator[]const char* を使用またはキャストして built を使用できchar*[]ます。

優先してほしいTest::operator[]です。

このような設定を指定する方法はありますか?

更新: まず、変換の優先度を指定できる言語機能がないという以下の回答に同意します。しかし、下記の juanchopanza のように、一方の変換ではキャストを必要とせず、もう一方の変換ではキャストを必要とするようにすることで、間接的にそのような設定を作成できます。たとえば、willunsigned intの引数としては機能しoperator[]ませんが、intwill を使用します。

デフォルトのインデックス引数は符号なしです - とにかく gcc と msvc の場合 - インデックス引数を符号なしにすると、コンパイラは正しい演算子を優先します。

@Konrad: 組み込み型への暗黙的な変換について。おおむね同意。しかし、この場合は必要です。

4

3 に答える 3

3

いいえ、ありません。そして、この種のあいまいさが、別の型 ( など) への自動変換がoperator char*推奨されない理由です。

于 2012-10-30T21:24:28.337 に答える
2

いつでもコンストラクターを作成できますexplicit。または、ジョンが指摘したように、変換演算子を省略できます。通常、これらすべてを実行することをお勧めしますが、コードはおもちゃの例であるため、状況に何が適切かを言うのは困難です.

つまり、次のように動作するはずです。

Test const& t2 = t.operator[](0);

(追加されていることに注意してください。constそうしないと、一時的に非 const 参照にバインドされ、どちらも機能しません。)

于 2012-10-30T21:25:25.417 に答える
1

I've implemented container classes like yours before -- it is entirely possible to avoid ambiguity problems while maintaining a clean, intuitive syntax.

First, you need to take const-ness into account. Usually, a const char* cast will not modify the object, so make this a const member function:

operator const char*() const;

Also, your [] operator is returning an int instead of int&, so this should probably be const too:

int operator[]( unsigned int ) const;

If you want to be able to assign a value to an indexed element (mytest[5]=2), you would add another operator function like this (this doesn't replace the const version above -- keep both):

int& operator[](unsigned int);

Next, you will want to accept indexes that are not just unsigned int. A literal integer has the int type. To avoid problems related to index type, you need to overload operator for alternatives. These overloads will just static_cast the index to your native index type and pass it to the native overload (the one for the native index type). One of these overloads might look like:

int operator[]( int idx ) const {
    return operator[]( static_cast<unsigned int>(idx) ); 
}

Instead of adding a bunch of overloads, you could use a single template member function to cover all possibilities. The template function will get used for any index types that do not already have a non-template overload. And this preference for non-template overloads is unambiguous. Essentially, this implements your request for a preferred operator, but const-ness is not templatable, so two versions would be required if you have a const and a non-const [] operator. This catch-all member function might look like this (keep in mind that its definition must stay in your class' declaration and cannot be moved to an implementation file):

template <typename IT>
int operator[]( const IT& idx ) const {
    return operator[]( static_cast<unsigned int>(idx) );
}

If you added a non-const version of the [] operator, then you would also need:

template <typename IT>
int& operator[]( const IT& idx ) {
    return operator[]( static_cast<unsigned int>(idx) );
}

Enjoy!

于 2012-10-31T01:17:17.657 に答える