4

次のコードを取ります。

class Foo
{
    Foo const& operator =(Foo const& rhs); // disallow
};

struct Bar
{
public:
    Foo foo;

    template <class T>
    T const& operator =(T const& rhs) { return rhs; }
};

struct Baz : public Bar {
    using Bar::operator =;
};

int main()
{
    Baz b1, b2;
    b1 = b2;
}

プライベートであるFoo::operator =を使用しようとする、Bar :: operator =の自動生成された代入演算子が使用されるため、これはコンパイルに失敗します。これで結構です。そこで、Barにメンバーを追加しました。

Bar const& operator =(Bar const& b) { return Bar::operator=<Bar>(b); }

今、私たちは別の問題を抱えています。2つのオーバーロードがあり、そのうちの1つだけを使用できます。私はBazconst&を渡します。私がC++について知っていることはすべて、一致する非テンプレートが最初に選択されるため、これは非テンプレートバージョンを使用することになるはずであることを示唆しています。これもgccが行っていることのようです。Visual Studioは同意しないようです:

error C2666: 'Bar::operator =' : 2 overloads have similar conversions
    could be 'const Bar &Bar::operator =(const Bar &)'
    or       'const T &Bar::operator =<Baz>(const T &)'
    with
    [
        T=Baz
    ]
    while trying to match the argument list '(Baz, Baz)'

ここでgccを信じたくなります。これは、C ++を理解していることがこれを裏付けていることと、Visual Studioと一致しない場合は一般的にgccを支持しているためですが、これについてはそれほど心配していません。

私の非最小の例では、正直なところ、デフォルトで生成された代入演算子はまったく必要ありません。テンプレート演算子が作業を行うことに満足しています。正しく実行されます。ただし、VSはテンプレートと自動生成された代入演算子の競合について不平を言っているため、実際にはそのテンプレートをまったく機能させることができません。私は次のすべてを試しました:

  1. 代入演算子をプライベートで実装されていないものにする(「すべてのオーバーロードが有効であるとは限らない」ため、機能しません)
  2. それを作成する(上記のエラーにつながる)
  3. 除外します(デフォルトで生成された代入演算子で上記​​のエラーが発生します)
  4. そのタイプのテンプレートの特殊化を作成し、デフォルトの代入演算子を正確に一致させます(コンパイラーによると明示的に違法です)

誰かが私がこの問題を回避する方法について何か明るい考えを持っていますか?残念ながら、私のバージョンのVSは、自動生成された代入演算子のC ++ 0x「削除」オーバーライドをサポートしていないため、これはオプションではなく、このエラーを回避する他の方法を考えることはできません。

4

1 に答える 1

2

代入演算子の 2 つのバージョン間で解決する際に見られるあいまいさは、Baz の定義で "using Bar::operator =

Bar で暗黙的または明示的に定義されているかどうかにかかわらず、非テンプレート バージョンは引数「const Bar&」を取ります。これは、「Baz」と完全に一致しません。

これには多くの方法がありますが、実際の解決策は実際のソースによって異なります。

この例を修正するには、次のことを行います。

const Bar& operator =(const Bar& b)o Foo の代入演算子を使用するため、の自動生成を防止します。Bar の定義に追加しようとしたものは機能します。

Bar const& operator =(Bar const& b) {
    return Bar::operator=<Bar>(b); 
}

o using Bar::operator =Baz の定義では移動する必要があります。Bar::operator= をラップする関数に置き換えます。そのような:

template <class T>
const T& operator =(const T& rhs) {
    return Bar::operator =(rhs); 
}

(もちろん、ファンキーでないコードは、引数の型ではなく、常に *this -- Bar& を返します。)

于 2012-06-26T07:11:30.923 に答える