Discussion
Team LiB
Previous Section Next Section

Discussion

In general, for some binary operator @ (be it +, -, *, and so on), you should define its assignment version such that a @= b and a = a @ b have the same meaning (other than that the first form might be more efficient and only evaluates a once). The canonical way of achieving this goal is to define @ in terms of @=, as follows:



T& T::operator@=( const T& ) {


 // … implementation …


 return *this;


}





T operator@( const T& lhs, const T& rhs ) {


 T temp( lhs );


 return temp @= rhs;


}



The two functions work in tandem. The assignment form does the actual work and returns its left-hand parameter. The non-assignment version creates a temporary from lhs, modifies it by invoking the assignment form, and returns it.

Note that here operator@ is a nonmember function, so that it will have the desirable property of accepting the same implicit conversions on its left-hand side and right-hand side parameters. (See Item 44.) For example, if you define a class String that has an implicit constructor taking a char, making operator+( const String&, const String& ) a nonmember enables both char + String and String + char to work; a member version String::operator+( const String& ) would only accept the latter. An efficiency-minded implementation might choose to define several nonmember overloads of operator@ to avoid proliferation of temporaries resulted through conversions (see Item 29).

Where possible, make operator@= a nonmember function as well (see Item 44). In any case, put all nonmember operators in the same namespace as T so that they will be conveniently available to callers as well as to avoid name lookup surprises (see Item 57).

A variation is to have operator@ accept its first parameter by value. This way, you arrange for the compiler itself to perform the copy for you implicitly, and this can give the compiler more leeway in applying optimizations:



T& operator@=( T& lhs, const T& rhs ) {


 // … implementation …


 return lhs;


}





T operator@( T lhs, const T& rhs ) {         // lhs taken by value


 return lhs @= rhs;


}



Another variation is to have operator@ return a const value. This technique has the advantage that it disables nonsensical code such as a + b = c, but it does so at the cost of disabling some potentially useful constructs such as a = (b + c).replace(pos, n, d)expressive code that, in one shot, concatenates strings b and c, replaces some characters, and assigns the final result to a.

    Team LiB
    Previous Section Next Section