Search code examples
c++compiler-errorstypedeffriend

Compiler error when declaring a friend function with a typedef'ed return type


Minimal example:

#include <cstdint>

std::int32_t someFunc();

namespace foo
{
class FooClass
{
private:
    void bar(){}
    friend std::int32_t ::someFunc();
};
}

std::int32_t someFunc()
{
    foo::FooClass c;
    c.bar();
    return 0;
}


int main(int argc, const char * argv[])
{
    return someFunc();
}

Building this code results in the following error: pathTo/fooClass.hpp:8:17: 'int32_t' (aka 'int') is not a class, namespace, or enumeration

Other info of interest:

  • Having failed to parse the friend declaration, the compiler also complains that bar() is private, which is expected.
  • If you change the friend declaration to "friend int ::someFunc();" the example code will compile without any other changes.
  • declaring "typedef int myInt;" and using myInt as the return type in the friend declaration also fails to compile with the same error.
  • Does not seem to be platform specific: occurs with both MacOS and Android toolchains

So this appears to be related to the fact that the return type in the friend declaration is a typedef, but I don't understand why that would be a problem. Can some one explain why the above code does not compile?

EDIT: As is often the case, I realized moments too late what the problem is. The compiler is parsing this code as if someFunc were a member of std::int32_t which is indeed not valid syntax. So my new question is, how would one do a friend declaration in a situation like this where :: MUST precede someFunc in the friend declaration to resolve properly?


Solution

  • Not sure if it's a bug or not. But when it comes to ambiguity in declarations, the solution is usually the correct use of parentheses. You can amend your friend declaration as follows

    friend std::int32_t (::someFunc)();
    

    Which will force the scope resolution operator to bind correctly to the declarator id instead of the type.

    Live example

    Parts of the declarator (even just the id) can be parenthesized in general, and sometimes they need to be in order to get the correct meaning. For instance, the age old difference between a function returning a pointer and a pointer to a function

    int *foo();
    int (*bar)();