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'; }