CRTP & copy/move assignment/constructor 继承

CRTP & copy/move assignment/constructor inheritance

我正在尝试使用 CRTP 在派生的 classes 的基础 class 中实现 move/copy 赋值运算符和构造函数。

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;
}

编译器给我一个错误,说 derived& derived::operator=(const derived&) 不能被 derived& base<derived>::operator=(const derived&) 覆盖。我的理论是,不知何故 derived::operator= 被隐式定义,然后通过 using 声明引入 base<derived>::operator= 我可能会再次尝试重新定义它?这看起来与意外定义方法两次时出现的错误非常相似。

我用 GCC 编译了这个,完整的日志是:

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) {
              ^~~~~~~~

这甚至有可能完成吗,还是我必须在 derived class 中定义 operators/constructors 然后将它们的功能委托给 base class里面的定义?

更新

OK,可能是看清楚了,还是觉得太复杂了。我可以执行以下操作:

Derived& base<Derived>::operator= (const base& other) {
    this->foo_ = other.foo_;
    return this->self();
}

因此返回的类型对于每个派生 class 都是正确的,并且复制是从基础 class 执行的 - 仅复制基础属性,这是我默认需要的。如果我需要更多,那么它特定于每个派生 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_;
}

但这仍然是一个有趣的练习,关于编译器错误的问题仍未得到解答。

您无法在基 class 中使用通常的签名有效地声明“派生 operator=”,因为即使使用 using-declaration ,就是 always hidden by the implicitly-declared copy assignment operator。 (您可以为它们中的一个或两个使用其他签名,但是重载解析可能会……很有趣。)

同时,您发现了一个 GCC 错误,它错误地得出两个运算符冲突而不是一个隐藏另一个的结论。