I am trying to implement a move/copy assignment operators and constructors in a base class for the derived classes using CRTP.
template <typename Derived>
class base {
public:
Derived& operator= (const Derived& other) {
// Copy the base properties:
this->foo_ = other.foo_;
// ...
// Continue as the derived class demands it:
this->derived().copy(other);
return this->derived();
}
// etc. for copy/move assignment/construction...
private:
// To act as the derived class:
Derived& derived () { return *static_cast<Derived*>(this); }
const Derived& derived () const { return *static_cast<const Derived*>(this); }
protected:
// Some base properties:
int foo_;
// ...
};
class derived: public base<derived> {
friend base<derived>;
public:
// Inheriting the constructors and assignment operators:
using base<derived>::base;
using base<derived>::operator=;
private:
void copy (const derived& other) {
// Copy all the needed derived properties:
this->bar_ = other.bar_;
// ...
}
// Some derived properties:
int bar_;
// ...
};
// To test it:
int main () {
derived d, t;
d = t;
}
Compiler gives me an error, saying that derived& derived::operator=(const derived&)
cannot be overwritten with derived& base<derived>::operator=(const derived&)
. My theory is, that somehow derived::operator=
gets defined implicitly and then by introducing the base<derived>::operator=
by the using
declaration I'm trying to redefine it again maybe? This looks suspiciously similar to errors that come up when accidentally defining a method twice.
I compiled this with GCC and the full log is:
test.cpp: In function 'int main()':
test.cpp:25:7: error: 'constexpr derived& derived::operator=(const derived&)' cannot be overloaded
class derived: public base<derived> {
^~~~~~~
test.cpp:4:14: error: with 'Derived& base<Derived>::operator=(const Derived&) [with Derived = derived]'
Derived& operator= (const Derived& other) {
^~~~~~~~
Is this even possible to accomplish, or do I have to define the operators/constructors in the derived
class and then delegate their functionality to the base
class inside the definition?
OK, maybe after looking at this with a clearer mind, it seems overly complicated. I could just do the following:
Derived& base<Derived>::operator= (const base& other) {
this->foo_ = other.foo_;
return this->self();
}
So the returned type is correct for every derived class and the copy is performed from the base class - only the base properties are copied, which is all I need by default. If I need more, then it's specific to each derived class:
// Adding this to the base class - for any derived class to act as the base one:
template <Derived>
base<Derived>& base<Derived>::base () { *return static_cast<base<Derived>*>(this); }
derived& derived::operator= (const derived& other) {
this->base() = other.base();
this->bar_ = other.bar_;
}
But still, it's an interesting excercise and the question regarding the compiler error remains unanswered.
You can’t usefully declare a “derived operator=
” with the usual signature in a base class because, even with a using-declaration, it is always hidden by the implicitly-declared copy assignment operator. (You could use some other signature for one or both of them, but then overload resolution is likely to be …interesting.)
Meanwhile, you’ve found a GCC bug in that it incorrectly concludes that the two operators conflict rather than one hiding the other.