【问题标题】:Is there a way to forward all assignment operators (+=, *=, etc.) to implicitly use an overridden direct assignment operator (=)?有没有办法转发所有赋值运算符(+=、*= 等)以隐式使用重写的直接赋值运算符(=)?
【发布时间】:2014-09-03 02:45:30
【问题描述】:

我知道“转发”在 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.

是否有“转发”所有赋值运算符(+=-=*=/=%=&gt;&gt;=&lt;&lt;=|=&amp;= , ^=) 这样我就不必定义它们了?也就是制作方法

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>

【问题讨论】:

  • 你可以用boost::operators做相反的事情(即定义+=并让+自动生成)。
  • 嗯,但目前看来我不需要生成+,因为转换操作为我方便地定义了+,其中基础数据类型T 具有适当的运算符。我希望有一种技术可以让我只定义直接赋值运算符。
  • @AndrewCheong 为什么不把operator+= 的body 变成*this = *this + val;,达到将x += y 解开为x = x + y 的目的。
  • (我认为这不是一个好主意,因为它比在不参考operator= 的情况下实现operator+= 更多操作,但这是您要求的!)

标签: c++ templates c++11 operator-overloading wrapper


【解决方案1】:

您可以使用 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';
}

另一个不容忽视的方法是宏......

【讨论】:

  • 为了确保我理解正确,如果我只希望 + 可以用于已经有这样一个运算符的类型 Teg doubleint 等,那么我根本不需要定义 Implied_Ops,对吗? (但我觉得这个建议很有价值。)或者,我误解了。
  • 错了...您需要Implied_Ops,但不需要定义如何添加/划分/多个/等类型,如doubleint。其他用户定义类型将需要最小的操作集,您可以从中定义Proxy 支持的扩展集。无论哪种方式,您都可以使用Implied_Ops / CRTP 将T 对+- 等操作的支持扩展Proxy,如图所示,使_data 可以通过get() 访问。在您的情况下,您还需要将 _state = State::SET; 添加到 operator= 的定义中。
【解决方案2】:

是的,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;
  }
};

然后从plus_equals&lt;Foo&gt;公开继承你的类Foo

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

【讨论】:

    猜你喜欢
    • 2016-11-02
    • 1970-01-01
    • 2012-11-02
    • 2013-04-29
    • 2013-11-09
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    相关资源
    最近更新 更多