If a class supports copy construction and if it offers binary assignment operators (i.e., it offers members of the form operator@=), then the matching binary operators can all be implemented identically. The move-aware Class &operator@(Class &&lhs, Class const &rhs) is easily implemented in terms of operator@= (note that the class itself doesn't have to be `move-aware' to define this function). The move-aware binary operator one requires a one line implementation, and as its implementation never changes it could safely be defined inline:
Class operator@(Class &&lhs, Class const &rhs)
{
return std::move(std::move(lhs) @= rhs);
}
The traditional binary operator can be implemented using its standard
form:
Class operator@(Class const &lhs, Class const &rhs)
{
Class tmp(lhs);
tmp @= rhs;
return tmp;
}
The implementation in bobcat/binops is slightly more complex as it
allows from lhs or rhs promotions.
As the binary operators can all be implemented alike their definitions are perfectly suited for templates: A class offering a particular operator@= then automatically also offers the matching binary operators after including bobcat/binops. Since the binary function templates are not instantiated until used their definitions can be processed by the compiler even if a class implements only a subset of the available binary assignment operators.
The binary operator functions templates in bobcat/binops are not implemented in a particular namespace. This allows sources to include bobcat/binops in multiple namespaces.
If bobcat/binops is to be used in multiple namespaces then the include safeguard (using the identifier INCLUDED_BOBCAT_BINOPS_) must be suppressed between inclusions of bobcat/binops in different namespaces.
E.g., to make the binary operator function templates available in a source file using the namespace FBB and in a source file using the default namespace the following scheme can be used:
#include <utility> // ensure std::move is available
#include <bobcat/typetrait> // required by binops
namespace MY_NAMESPACE
{
#include <bobcat/binops> // binary operators available in MY_NAMESPACE
}
#undef INCLUDED_BOBCAT_BINOPS_ // suppress the include guard
#include <bobcat/binops> // read binops again so the binary
// operators can be used in the
// default namespace as well
Move-aware operators, using temporary objects for its left-hand side operands:
`Traditional' operators, using lvalue references to constant objects for its left-hand side operands:
#include <iostream>
#include <utility>
#include "../../typetrait/typetrait"
#include "../binops"
class Demo
{
friend std::ostream &operator<<(std::ostream &out, Demo const &demo);
int d_value;
public:
Demo(int value = 0)
:
d_value(value)
{}
Demo(Demo const &other)
:
d_value(other.d_value)
{
std::cout << "Demo CC called\n";
}
Demo &operator+=(Demo const &rhs)
{
d_value += rhs.d_value;
return *this;
}
};
std::ostream &operator<<(std::ostream &out, Demo const &demo)
{
return out << demo.d_value;
}
using namespace std;
int main()
{
Demo four(4);
Demo five(5);
cout << four + five << '\n' <<
four + 5 << '\n' <<
4 + five << '\n';
}