[intrusive_ptr] Why are comparison operators not friends?

Hi all, I was just (re-)reading item 46, "Define non-member functions inside templates when type conversions are desired", in Scott Meyers "Effective C++, 3rd edition", and was wondering how and why the comparison operators for intrusive_ptr work when used with NULL, even though they're not friend functions as described in Scott Meyer's item 46. That is, the example program below compiles and links fine both with GCC 4.6 as well as with Visual C++ 2010 -- but how does do the compilers match the == operator, whose right operand is NULL, an int value? If I try to use the exact same templated binary operators like this in my own classes, and want NULL matched to one of the T* or U* operands, then I have to do it with friend functions or else the compilers don't find a match. Why does it work here? Best regards, Carsten #include <boost/intrusive_ptr.hpp> #include <iostream> class CRefCounted { public: CRefCounted() : RefCount(0) {} long RefCount; }; void intrusive_ptr_add_ref(CRefCounted* p) { ++(p->RefCount); } void intrusive_ptr_release(CRefCounted* p) { if (--(p->RefCount) == 0) delete p; } int main() { using namespace boost; intrusive_ptr<CRefCounted> p(new CRefCounted()); // I'd expect the next line of code to fail compilation, because the compiler // cannot find a match for operator == with left operand of type // intrusive_ptr<CRefCounted> and right operand of type int, but they do! if (p == NULL) std::cout << "p == NULL\n"; else std::cout << "p != NULL\n"; }

I was just (re-)reading item 46, "Define non-member functions inside templates when type conversions are desired", in Scott Meyers "Effective C++, 3rd edition", and was wondering how and why the comparison operators for intrusive_ptr work when used with NULL, even though they're > not friend functions as described in Scott Meyer's item 46. I believe you're talking about the ancient technique of friend injection used here for example: http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick
The modern good way of doing this Koenig lookup which I think deprecates that trick. http://en.wikipedia.org/wiki/Argument-dependent_name_lookup Just define the operator== in the namespace of the type it works on. It'll find that name in the first lookup stage and then look for a fitting overload. In your code the first one is taken. Though I'm not sure what U is; I'm guessing void. template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, U * b); template<class T, class U> inline bool operator==(T * a, intrusive_ptr<U> const & b); Chris

Hi Christopher, Am 2012-08-09 12:47, schrieb Hite, Christopher:
I was just (re-)reading item 46, "Define non-member functions inside templates when type conversions are desired", in Scott Meyers "Effective C++, 3rd edition", and was wondering how and why the comparison operators for intrusive_ptr work when used with NULL, even though they're > not friend functions as described in Scott Meyer's item 46. I believe you're talking about the ancient technique of friend injection used here for example: http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick
The modern good way of doing this Koenig lookup which I think deprecates that trick. http://en.wikipedia.org/wiki/Argument-dependent_name_lookup
Thank you very much for your reply! I still have to experiment and compare and check my code, but the linked articles and their references help a lot! Thanks! Best regards, Carsten -- Cafu - the open-source Game and Graphics Engine for multiplayer, cross-platform, real-time 3D Action Learn more at http://www.cafu.de
participants (2)
-
Carsten Fuchs
-
Hite, Christopher