Friends and namespaces

There are C++ behaviors that may leave you a bit astonished, staring at the lines on the monitor and wondering why the code isn’t compiling, or doesn’t work as expected. Just stumbled in one of these cases.
I usually follow these steps to recover from the puzzled face. First I write a minimal example that reproduces the behavior. It should be a bunch of lines in a single file. Sometimes this could be a daunting task, but I have that it is always worth to grasp the problem.
In fact, once you have the minimal code, you can easily experiment, changing and twiddling bits to see how the behavior changes.
Then you have two options – you can ask your local C++ guru about the problem (if you have one), or you can google the Internet for a clever selection of keywords that describes your problem.
So what happened today?
I decide to move some code I developed into a namespace-constrained library. Everything compiled happily outside the namespace, but failed to do so in the namespace. After some headscraping, I started cutting and shaping a minimum file with the same odd behavior. Here you are:

/** prova.cc
 *
 * @author Massimiliano Pagani
 * @version 1.0
 * @date 24/04/2007
 *
 * @notes
 * @history
 *
*/

#if defined( USE_NAMESPACE )
namespace NS
{
#endif

    class A
    {
        public:
        private:
            struct B { int x; };
            friend bool fn( B const& b );
    };

#if defined( USE_NAMESPACE )
}

using namespace NS;

#endif

namespace NS
{

    bool fn( A::B const& b )
    {
        return b.x != 0;
    }
}

Now, if you compile it defining the symbol USE_NAMESPACE (e.g. via g++ -Wall -DUSE_NAMESPACE -c prova.cc), then you get the odd looking error:

prova.cc: In function 'bool fn(const NS::A::B&)':
prova.cc:21: error: 'struct NS::A::B' is private
prova.cc:31: error: within this context

While if you compile without the namespace everything works as expected. Since the error was quite meaningless to me, I started investigating on friend and namespace. After some mailing list browsing, I figure it out. And it was simpler than what appeared – just a case for a misleading error.
In fact the friend statement declares a function fn somewhere in the NS namespace, while actually fn is defined in the global namespace. In fact there is just a using statement. To fix the problem, just move the fn function into the NS namespace.
Well and I have figure it out alone, without the need of calling my uber-C++-guru friend Alberto.
On a completely unrelated topic, today is the 25th anniversary of the marvelous ZX Spectrum. Happy Birthday Dear Speccy.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.