私が行ったばかりのテストまで、コンストラクターだけがC++で継承されていないと信じていました。しかし、どうやら、割り当てoperator=
もそうではありません...
operator+=
、operator-=
、...の場合もそうですか?実際、CRTPを実行していたときにこの問題が発生しました。
template<class Crtp> class Base
{
inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
};
class Derived1 : public Base<Derived1>
{
};
class Derived2 : public Base<Derived2>
{
};
それを機能させるための解決策はありますか?
編集:OK、私は問題を切り分けました。以下が機能しないのはなぜですか?問題を解決するには?
#include <iostream>
#include <type_traits>
// Base class
template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
{
// Cast to base
public:
inline Base<CRTP, T, N>& operator()()
{
return *this;
}
// Operator =
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline CRTP<T, N>& operator=(const T0& rhs)
{
for (unsigned int i = 0; i < N; ++i) {
_data[i] = rhs;
}
return static_cast<CRTP<T, N>&>(*this);
}
// Data members
protected:
T _data[N];
};
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
};
// Main
int main()
{
Derived<double, 3> x;
x() = 3; // <- This is OK
x = 3; // <- error: no match for 'operator=' in ' x=3 '
return 0;
}
代入演算子は技術的に継承されます。ただし、派生クラスの明示的または暗黙的に定義された代入演算子によって常に非表示になっています(以下のコメントを参照)。
(13.5.3代入)代入演算子は、パラメータが1つだけの非静的メンバー関数によって実装されます。コピー代入演算子
operator=
は、ユーザーによって宣言されていない場合、クラスに対して暗黙的に宣言されるため、基本クラス代入演算子は、派生クラスのコピー代入演算子によって常に非表示になります。
次のように、呼び出しを基本クラスoperator=
に転送するだけのダミー代入演算子を実装できます。
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline Derived& operator=(const T0& rhs)
{
return Base<Derived, T, N>::operator=(rhs);
}
};
代入演算子isは継承された、ソートですが...与えられたどのクラスでも、コピー代入演算子を指定しない場合、コンパイラーが生成します。つまり、派生クラスには実質的に代入演算子があります。
Derived& operator=( Derived const& );
そして、通常の隠蔽規則が適用されます。これにより、すべての基本クラス割り当て演算子が非表示になります。 (基本クラスにこのシグニチャーの割り当て演算子がある場合、派生クラスは通常それを継承します。)
割り当て演算子は技術的に継承されますが、派生クラスのデフォルトのコピー割り当て演算子によって非表示になります。次に、このデフォルトのコピー割り当ては、独自の割り当てで非表示にしたために存在しない基本クラスのコピー割り当てを呼び出そうとします。
これを解決する最も健全な方法は、明白でない方法で演算子のオーバーロードを使用しないことです(たとえば、=
はコピー割り当てを意味しません)。この場合は、operator=
を使用しないでください。assign
やset
などの名前を付けると、継承され、子のコピー割り当てによって非表示になりません。
これらの演算子は継承され、コンパイラバージョンがないため、operator=
のように自動的に非表示になることはありません。
それは実際には継承されないコンストラクターだけであり、operator=
のように親から何かを隠すことができる他のコンパイラー生成関数は考えられません。