HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Avoid duplicated += -= operator code

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
duplicatedcodeoperatoravoid

Problem

In C++ (and C++11), classes defining a + and += operators often define a - and -= operators that do nearly the same thing (except + is replaced with - in the function).

What is the best way to avoid duplicated code here (and still achieve good performance)? I am sure there is a good way to do it with functors:

Here's what I've tried:

#include 
#include 

struct num {
  int val;

  const num & operator +=(const num & rhs) {
    return op_equals >(rhs);
  }
  const num & operator -=(const num & rhs) {
    return op_equals >(rhs);
  }

  template 
  const num & op_equals(const num & rhs) {
    op operation;
    val = operation(val, rhs.val);
    return *this;
  }
};

int main() {
  num x{1};
  num y{2};
  x += y;

  std::cout << x.val << std::endl;
  return 0;
}


Note that this is a simple example; in reality the code in the += and -= operators is more complex.

Also, I am not married to functors in the solution-- any suggestions or advice?

Solution

I actually quite like this pattern and use it relatively often. I'm not sure if there is something better than functors for this - if there is, I'm not really aware of it. That being said, with C++11, I'd write this in a slightly different way:

struct num {
  int val;

  const num& operator +=(const num & rhs) {
    return op_equals(rhs, std::plus());
  }

  const num& operator -=(const num & rhs) {
    return op_equals(rhs, std::minus());
  }

  template 
  const num & op_equals(const num & rhs, op&& o) {
    val = o(val, rhs.val);
    return *this;
  }
};


Note the rvalue reference (which is actually a "universal reference", so can bind to either an lvalue or rvalue reference), and the movement of op to a parameter - I don't really like having to specify it as a template parameter which then gets instantiated and called in the function. I think this way is slightly cleaner.

Code Snippets

struct num {
  int val;

  const num& operator +=(const num & rhs) {
    return op_equals(rhs, std::plus<int>());
  }

  const num& operator -=(const num & rhs) {
    return op_equals(rhs, std::minus<int>());
  }

  template <typename op>
  const num & op_equals(const num & rhs, op&& o) {
    val = o(val, rhs.val);
    return *this;
  }
};

Context

StackExchange Code Review Q#13140, answer score: 3

Revisions (0)

No revisions yet.