C++ friend function reference to global enum from inside namespace

Viewed 157

The following friend declaration for FriendlyAccess compiles under C++98 (gcc 4.4.7):

typedef enum MyError
{
    SUCCESS = 0,
    FAILURE = 1
} MyError;

MyError FriendlyAccess();

namespace outer {

class ClassA
{
public:

    friend MyError ::FriendlyAccess();  // enum MyError is not a class or namespace

protected:

    int protectedMember();
};

} // Added missing terminator for namespace outer

using outer::ClassA;

int
ClassA::protectedMember()
{
    return 0;
}

MyError FriendlyAccess()
{
    ClassA a;

    std::cout << "Access Protected Method " << a.protectedMember() << std::endl;

    return SUCCESS;
}

The enumeration reference in the friend declaration will not compile under C++14 (gcc 8.3.1):

friend.cpp:17:37: error: ‘enum MyError’ is not a class or a namespace
     friend MyError ::FriendlyAccess();
                                     ^
friend.cpp:17:37: error: ISO C++ forbids declaration of ‘FriendlyAccess’ with no type [-fpermissive]
friend.cpp: In function ‘MyError FriendlyAccess()’:
friend.cpp:38:66: error: ‘int outer::ClassA::protectedMember()’ is protected within this context
     std::cout << "Access Protected Method " << a.protectedMember() << std::endl;
                                                                  ^
friend.cpp:29:1: note: declared protected here
 ClassA::protectedMember()

Declaring ClassA in the global namespace allows the code to compile successfully. Is there a correct way to reference the C style enum from inside the namespace on a friend declaration in later versions of C++?

UPDATE

  • C-style enums are legacy code

  • Added missing "}" terminator for namespace outer

  • Removing the "::" global scope delimiter allows the friend declaration to compile, but grants friendship to outer::FriendlyAccess instead

  • Trailing return type, as suggested by IICapitano, does compile successfully

    friend auto ::FriendlyAccess() -> MyError;

1 Answers

The friend statement takes a function declaration or definition.

When removing the ::, you end up declaring another FriendlyAccess function, this time from inside the outer namespace. That works if you put the FriendlyAccess definition inside the workspace too (then your initial declaration in the global namespace is unused).

The compiler seems to interpret friend MyError ::FriendlyAccess(); as trying to friend a member method of class MyError (which is legal) and doesn't see that it could also be your existing free function.

Using auto and trailing return type makes it understand it's a free function

friend auto ::FriendlyAccess() -> MyError;
Related