I'm trying to understand some boost code which is causing PC-Lint grief and uses the friend keyword in a way which I didn't think was legal C++ but compiles OK in VS2008.
I thought I understood friend as a way to declare classes and functions. I didn't think it was legal to use on a function definition like this. However, the MSDN page is very specific:
Friend functions can be defined inside class declarations. These functions are inline functions, and like member inline functions they behave as though they were defined immediately after all class members have been seen but before the class scope is closed (the end of the class declaration).
Friend functions defined inside class declarations are not considered in the scope of the enclosing class; they are in file scope.
So I understand that it is legal, if unusual syntax.
I'm not sure what it gets them because the normal reason for declaring something a friend is to give it increased access. However, the members of a struct are all public by default so there's no such benefit here.
Am I missing something profound or is this just some stylistic boost issue where someone doesn't like putting inline free functions after the body of the struct?
Note that _InterlockedIncrement is an intrinsic function on Win32.
# define BOOST_INTERLOCKED_INCREMENT _InterlockedIncrement
struct thread_data_base
{
long count;
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
virtual ~thread_data_base()
{}
friend void intrusive_ptr_add_ref(thread_data_base * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->count);
}
...
};
update
Thanks to Chubsdad's answer below, I think I understand it now, my summary of what's happening:
intrusive_ptr_add_ref(somePtrToThreadData)
It is perfectly fine to define 'friend' functions inside a class definition. In this particular case, since the friend function takes a parameter of type thread_data_base
, the friend function definition is visible only in case of ADL (argument dependent lookup) $3.4.2 when called from outside the lexical scope of the class definition
Check out Namespace and the Interface Principle from Herb Sutter