【问题标题】:Non-friend single-line operator + overload based on operator +=非友元单行运算符 + 基于运算符的重载 +=
【发布时间】:2016-03-27 16:44:14
【问题描述】:

假设我有一堂课:

class A
{
    //...
};

定义明确的operator +=:

A& operator +=(const A&) {return *this;} //class without members

所以让我们也尝试重载operator+(作为非朋友)。我不想使用类名来调用临时对象的构造函数(有点想要这个通用代码):

A operator +(const A& other) const
{
    return auto(*this)(*this) += other; //error: invalid use of auto
//         /\/\/\/\/\    /\      
//        type of *this  ||
//                 constructor call
}

auto 在这里不好。让我们试试decltype

A operator +(const A& other) const
{
    return decltype(*this)(*this) += other; //error: 'A& A::operator+=(const A&)' discards
//         /\/\/\/\/\/\/\    /\                      qualifiers [-fpermissive] return
//          type of *this    ||                      decltype(*this)(*this) += other;
//                    constructor call                                      ^
}

这设法从*this 中取出类型,但是operator+ 被声明为const,所以我们推导出了const A(这就是我的想法)。那么让我们继续吧:

A operator +(const A& other) const
{
    return typename std::remove_const<decltype(*this)>::type(*this) += amount; 
    //same error as previous
}

现在我被吓坏了。即使我删除了 constness,它仍然丢弃 限定符。好吧,也许那是因为我所做的只是铸造。如此愚蠢。要调用构造函数,我必须生成(除了类型)具有 ::Constructor 的代码(所以我什至尝试为构造函数创建别名,但此时我失败了)。我破碎的大脑放弃了,但我的其余意识给了我一个解决方案(这在写作中是通用的,所以这很好):

// outside of class
template<class A>
inline A&& make_rvalue(A copy)
{
    return std::move(copy);
}

// inside of class
A operator +(const A& other) const
{
    return make_rvalue(*this) += other; // such generic code
}

这就是我的结局。但是有什么不涉及任何其他函数调用的技巧吗?

编辑:我知道这样做的经典方法,但我搜索的内容如下所述:

  • 操作员被缩减为{return /*...*/;}
  • 不涉及类方法或全局函数的名称
  • 考虑到其他类型的重载 - 它不能按值接受参数,因为class A != class B,参数int over const int&amp;Matrix 类没有多大帮助(但调用的代理运算符具有交换参数的目标运算符是可以的)
  • 考虑到(可能的)操作顺序 (x@y != y@x),两者应该有相同的返回语句
  • return 语句应该完全相同,因为给定的 operator@ 是每个重载 operator += 的类

【问题讨论】:

  • 为什么不首先按值取参数,而不是 const ref?
  • 不知道你在说什么。
  • 这个operator+ 不是通用的;它传输A 类型的对象。没有充分的理由避免使用 A 类型,因为您确切地知道它是什么。即使在通用代码中,您也会知道您正在处理的类型。所有这些迂回都是毫无意义的。
  • 从逻辑上讲是有道理的。您复制*this 并添加到其中。没有什么不对。 @Useless 嗯...大声笑,这太完美了!几乎可以解决它,但我仍然很想知道是否可以在不调用任何其他函数(包括构造函数)的情况下从 const 引用中创建一个非常量临时变量。编辑:嗯,这适用于A@A 运算符,但是A+number 呢?从数字到 A 的隐式转换完全很糟糕。 EDIT2:此外,当操作 A@B 不等于 B@A 时,这也不起作用。

标签: c++ c++11 operator-overloading c++14


【解决方案1】:

如果你创建一个这样的函数:

template <typename T>
T add(T temp,const T &b)
{
    temp += b;
    return temp;
}

你可以这样使用它:

  A operator+(const A& other) const { return add(*this,other); }

【讨论】:

  • 这个我很了解,从c++11出来就一直在用那个版本。我搜索的是return /*...*/;的版本@
  • @BlackMoses:好的,我已经将答案更改为匹配。
【解决方案2】:

我要郑重声明,这整个思路/编码方式都走错了路。您已经知道(在这种情况下)返回类型是A。您的代码似乎在尽可能以最复杂、最间接的方式说出A 方面投入了大量工作。

A operator +(const A& other) const {
    A ret {*this};
    ret += other;
    return ret;
}

因为你似乎真的想要使用 C++11 特性(尽管在这种情况下几乎没有一个提供任何真正的帮助)我使用了一个花括号初始化器,所以它使用了 来自 C++11 的东西。不,这不是一行,但它是可读的。

请注意,在通用代码中也可以使用相同的样式。例如,在operator+ 的非成员重载中,我们可能会有这样的情况:

template <class T>
T operator+(T const &a, T const &b) { 
    T ret {a};
    ret += b;
    return ret;
}

这也可以稍微简化一下:

template <class T>
T operator+(T ret, t const &b) { 
    ret += b;
    return ret;
}

再一次,我们完全什么都没有,因为旧的编译器可以并且将毫无问题地接受代码。

【讨论】:

  • 好的,但是如果 operator+ 涉及两种类型,并且操作顺序会产生巨大的差异,请考虑调用可能的代理运算符,它会调用带有交换参数的实际运算符 - 简单的模板不会知道什么是好的顺序,并且这样的代理模板将与原始模板完全相同,但不知道它是否实际上是代理。太模棱两可了。
  • @BlackMoses - 是的,如果问题不同,答案可能会不同。但事实并非如此。
猜你喜欢
  • 1970-01-01
  • 2016-01-24
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
  • 2011-04-28
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多