views:

78

answers:

1

I am trying to declare a global function as a "friend" of a class:

namespace first
{
    namespace second
    {
        namespace first
        {
            class Second
            {
                template <typename T> friend T ::first::FirstMethod();
            };
        }
    }
}

When I compile this code under Visual C++ 2008 I get:

error C3254: 'first::second::first::Second' : class contains explicit override 'FirstMethod' but does not derive from an interface that contains the function declaration
error C2838: 'FirstMethod' : illegal qualified name in member declaration

If I use template <typename T> friend T first::FirstMethod(); instead I get:

error C2039: 'FirstMethod' : is not a member of 'first::second::first'

What is the appropriate way of declaring friend functions?

+5  A: 

You have hit my quiz by accident - the sequence T ::first:: ... is interpreted as a single name. You need to put some token in between the colons and T. Solution is presented in the linked question too.

Notice that in any case you first have to declare the function designated by a qualified name in its respective namespace, too.


Edit: There are different solutions for the syntax problem

 template <typename T> friend T (::first::FirstMethod)();
 template <typename T> T friend ::first::FirstMethod();

If you often need to refer to the outer namespace and have problems with this syntax, you can introduce a namespace alias

    namespace first
    {
        namespace outer_first = ::first;
        class Second
        {
            template <typename T> friend T outer_first::FirstMethod();
        };
    }
Johannes Schaub - litb
Excellent answer. Thank you very much!
Gili
why is `T ::first::` interpreted as a single name ? if it were a single name there would need to be the `typename` prefix wouldnt it ?
smerlin
@smerlin, it's a non-type name. That means that the declaration declares the name `T::first::FirstMethod`, and specifies no type for that name. Semantically that makes no sense, and makes VC++08 spit out confusing error messages. Clang's diagnostic is much better: "error: C++ requires a type specifier for all declarations". Of course you can prefix it by "typename", in which case it acts as a type-specifier and the member-name is missing. Clang then says "error: expected member name or ';' after declaration specifiers"
Johannes Schaub - litb