是否有方法将所有赋值运算符(+=、*=等)转发为隐式使用重写的直接赋值运算符(=)

Is there a way to forward all assignment operators (+=, *=, etc.) to implicitly use an overridden direct assignment operator (=)?

本文关键字:赋值运算符 重写 有方法 是否 转发      更新时间:2023-10-16

我知道"转发"在C++11中是一个无关的概念(就像在"完美转发"中一样),但它是我描述这个问题时想到的第一个词。

我正在重写包装类Proxy,中的operator=

template<typename T>
class Proxy
{
public:
    enum class State
    {
        NEVER_SET = 0,
        SET
    };
    operator const T& () const
    {
        if ( _state != State::SET )
        {
            throw std::domain_error{ "using unset data" };
        }
        return _data;
    }
    Proxy<T>& operator=(const T& val)
    {
        _data = val;
        _state = State::SET;
        return (*this);
    }
private:
    T _data;
    State _state = State::NEVER_SET;
};

但我发现自己也需要添加:

    Proxy<T>& operator+=(const T& val)
    {
        _data = (*this) + val;
        _state = State::SET;
        return (*this);
    }
    Proxy<T>& operator-=(const T& val)
    {
        _data = (*this) - val;
        _state = State::SET;
        return (*this);
    }
    Proxy<T>& operator*=(const T& val)
    {
        _data = (*this) * val;
        _state = State::SET;
        return (*this);
    }
    Proxy<T>& operator/=(const T& val)
    {
        _data = (*this) / val;
        _state = State::SET;
        return (*this);
    }
    // ...and so on.

有没有一个技巧可以"转发"所有赋值运算符(+=-=*=/=%=>>=<<=|=&=^=),这样我就不必定义它们了?也就是说,一种制作的方法

Proxy<double> x = 7;
Proxy<double> y = 43;
x += y;

自动"解开"到

Proxy<double> x = 7;
Proxy<double> y = 43;
x = x + y; // cast operator converts x and y to double, then direct assigns sum,
           // therefore no += needing definition in Proxy<T>

您可以使用CRTP,但如果您的目标是在Proxy类中只有一个显式=,则需要提供对其他运算符已经可用的类型的一些访问权限。换句话说,如果您定义了如何分配,但没有定义如何添加,则不能说a1 = a2 + a3。我在下面通过期望一个get()函数来解决这个问题,该函数公开了一些可以操作的状态。显式定义(例如+=)比用它定义+更典型(也可能更实用)…

#include <iostream>
template <typename T>
struct Implied_Ops
{
    T operator+(const T& rhs) const
    {
        return rhs.get() + static_cast<const T*>(this)->get();
    }
    T& operator+=(const T& rhs)
    {
        return static_cast<T&>(*this) = operator+(rhs);
    }
};
struct X : Implied_Ops<X>
{
    X(int n) : n_(n) { }
    X& operator=(const X& rhs) { n_ = rhs.n_; return *this; }
    int get() const { return n_; }
    int n_;
};
int main()
{
    X x { 10 };
    X x2 = x + x;
    X x3 = x + x2;
    std::cout << x.n_ << ' ' << x2.n_ << ' ' << x3.n_ << 'n';
}

另一种不应忽视的方法是宏。。。。

有CRTP。

template<class D>
struct plus_equals {
  template<class Rhs>
  D& operator+=(Rhs&& rhs){
    D*self=static_cast<D*>(this);
    self->_data = (*self)+std::forward<Rhs>(rhs);
    self->_state= State::SET;
    return *self;
  }
};

然后从CCD_ 19公开继承您的类CCD_。

当然,您需要为每个运算符编写样板文件,因此它对一种类型没有多大帮助。