411 REFERENCE · Wikibooks
More C++ Idioms/Barton-Nackman trick
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
Barton-Nackman trick
Intent
Support overloaded operators without relying on namespaces or function template overload resolution.
Also Known As
The inventors originally referred to it as Restricted Template Expansion, though this term has never been widely used.
Motivation
John Barton and Lee Nackman first published this idiom in 1994 in order to work around limitations of the C++ implementations available at the time.Barton John J. Nackman Lee R. Scientific and Engineering C++: An Introduction with Advanced Techniques and Examples Addison-Wesley 1994 0-201-53393-6 Though it is no longer necessary for its original purpose, the current standard retains support for it.
At the time Barton and Nackman originally developed the idiom, C++ did not support overloading of function templates and many implementations still didn't support namespaces. This caused problems when defining operator overloads for class templates. Consider the following class:
template<typename T>
class List {
// ...
};
The most natural way to define the equality operator is as a non-member function at namespace scope (and since compilers at the time didn't support namespaces, therefore at global scope). Defining operator== as a non-member function means that the two arguments are treated symmetrically, which doesn't happen if one argument is a this pointer to the object. Such an equality operator might look like this:
template<typename T>
bool operator==(List<T> const & lft, List<T> const & rgt) {
//...
}
However, since function templates couldn't be overloaded at the time, and since putting the function in its own namespace wouldn't work on all platforms, this would mean that only one class could have such an equality operator. Doing the same thing for a second type would cause an ambiguity.
Solution and Sample Code
The solution works by defining an operator in the class as a friend function:
template<typename T>
class List {
public:
friend bool operator==(const List<T> & lft,
const List<T> & rgt) {
// ...
}
};
Instantiating the template now causes a non-template function to be injected into global scope with the argument types being concrete, fixed types. This non-template function can be selected through function overload resolution the same way as any other non-template function.
The implementation can be generalised by providing the friend functions as part of a base class that is inherited from via the Curiously Recurring Template Pattern:
template<typename T>
class EqualityComparable {
public:
friend bool operator==(const T & lft, const T & rgt) { return lft.equalTo(rgt); }
friend bool operator!=(const T & lft, const T & rgt) { return !lft.equalTo(rgt); }
};
class ValueType :
private EqualityComparable<ValueType> {
public:
bool equalTo(const ValueType & other) const;
};
Known Uses
Boost.Operators library
Related Idioms
Curiously Recurring Template Pattern
See also
Barton-Nackman trick on Wikipedia.
References