3

3 つのクラス (A、B、C) を持つクラス階層があります。A と B は、派生した Type でパラメーター化された基本クラスです。クラス C は、A と B の両方から派生します。

クラス B は型 A のオブジェクトの代入演算子を提供し、クラス C はこの代入演算子をusing super::operator=宣言と共に継承します。

タイプ A のオブジェクトからクラス B でコンストラクターを定義すると、Visual Studio 2013 でエラー: 2 つのオーバーロードが同様の変換を持っています(C2666) が表示されますが、gcc (4.8.2) でエラーや警告が表示されません。 、clang (3.4) および intel icc (Studio 2015)。(でコンパイル-Wall -pedantic)

ここに削減された例:

template <class Model> struct A {};

template <class Model> struct B
{
    B() {}; // default constructor

    // copy constructor for objects of type A
    template <class M> 
    B(A<M> const&) {} 

    // assignment operator for objects of type A
    template <class M>
    Model& operator=(A<M> const& rhs)
    {
        return static_cast<Model&>(*this);
    }
};

struct C : public B<C>, public A<C>
{
    typedef B<C>  super;

    // copy assignment operator
    C& operator=(C const& rhs) { return *this; }

    // adopt assignment operator for A<C> from super-class
    using super::operator=;
};

int main()
{
    C c;
    A<C> a;
    c = a;
}

テンプレート化されたクラス A をテンプレート化されていないクラスに置き換えると、Visual Studio でもエラーなしでコンパイルされますが、これは解決できる方法ではありません。

私の質問は次のとおりです。この構成は、標準に準拠しているという意味で整形式ですか、それともエラーメッセージは正しいですか? B のコピー コンストラクターのような指定子はexplicit、問題の解決に役立ちますか?

ところで、Visual Studio では、クラス C のコピー代入演算子が原因で、警告:複数の代入演算子が指定されました (C4522) が表示されます。

4

1 に答える 1

1

GCC と CLANG は正しく、MSVC は間違っています。

予想される動作は何ですか:

anは であるとは限らないため、ステートメントは で定義した をc=a;使用します。それでは、手動で型置換を行ってofの宣言を書き留めましょう。operator=BA<C>Coperator=B<C>

template <class M> 
C& operator=(A<M> const& rhs)

のようaA<C>、このテンプレートの明白な暗黙的なインスタンス化の候補は次のようになります。

 C& operator=(A<C> const& rhs)

実際、これが可能な唯一のインスタンス化です (typeinfo を表示することで、GCC がそれを使用していることを確認できます)。

MSVC は何をしようとしていますか?

クラス C を簡素化してさらに最小限の形式に変更した場合でも、エラーが発生します。

struct C : public B<C>   // single inheritance
{   using B<C>::operator=; };  // nothing else

実際、問題はコンストラクタによって引き起こされますB(A<M> const&):

  • コメントアウトすると、コードがコンパイルされます
  • 明示的にすると、コードもコンパイルされます

MSVC は、メンバー関数の暗黙的な特殊化の 2 番目の潜在的な候補を誤って識別します。このコンストラクターは から への暗黙的な変換を許可するため A<M>B<C>候補は次のとおりです。

 C& operator=(B<C> const& rhs)

しかし、C++ 標準によれば、これはコンパイラによって想定されるべきではありません。

14.8.1/6: テンプレート引数推定に関与するテンプレートパラメーターがパラメーターの型に含まれていない場合、関数の引数に対して暗黙的な変換が実行され、対応する関数パラメーターの型に変換されます。

したがって、これは明らかに MSVC のバグです。

ところで:

複数の代入演算子に関する警告は単なる情報です。どうやら MS は、これが間違いの頻繁な原因である可能性があると想定しています。そして今、核心的な質問に...

于 2015-04-01T22:00:11.990 に答える