2

我正在尝试在使用 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;
}

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

我用 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类中定义运算符/构造函数,然后将它们的功能委托给base定义中的类?

更新

好吧,也许在用更清晰的头脑看这个之后,它似乎过于复杂。我可以做到以下几点:

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

所以返回的类型对于每个派生类都是正确的,并且复制是从基类执行的——只复制基本属性,这是我默认需要的。如果我需要更多,那么它特定于每个派生类:

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

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

4

1 回答 1

1

您不能operator=在基类中使用通常的签名有效地声明“派生”,因为即使使用using-declaration,它也总是被隐式声明的复制赋值运算符隐藏。(您可以为其中一个或两个使用其他签名,但是重载决议可能会……很有趣。)

同时,您发现了一个 GCC 错误,它错误地断定两个运算符冲突,而不是一个隐藏另一个。

于 2019-05-03T04:22:11.400 回答