1

I am trying to declare a function within unnamed namespace as a friend of a class inside a named namespace but it fails.

I am using "gcc (GCC) 13.1.1 20230429"

Please consider the code below (all within a same file):

namespace {
void afunc(auto&);
}

namespace aspace{
class aclass{
    int a;
    friend void afunc(auto&);
};
}

namespace {
void afunc(auto& ref){
    ref.a = 12;
}

void bfunc(aspace::aclass& ref) {
    afunc(ref);
}
}

Which gives this error:

error: call of overloaded ‘afunc(aspace::aclass&)’ is ambiguous
note: candidate: ‘void {anonymous}::afunc(auto:16&) [with auto:16 = aspace::aclass]’
note: candidate: ‘void aspace::afunc(auto:17&) [with auto:17 = aclass]’

the first note: candidate: ‘void {anonymous}::afunc(auto:16&) [with auto:16 = aspace::aclass]’ refers to the definition of the afunc and interestingly the later note: candidate: ‘void aspace::afunc(auto:17&) [with auto:17 = aclass]’ refers to the friend declaration inside aclass(same line number)!

If I name the unnamed namespace, code will compile flawlessly:

namespace bspace{
void afunc(auto&);
}

namespace aspace{
class aclass{
    int a;
    friend void bspace::afunc(auto&);
};
}

namespace bspace{
void afunc(auto& ref){
    ref.a = 12;
}

void bfunc(aspace::aclass& ref) {
    afunc(ref);
}
}

I tried using ::afunc instead of afunc in different places within the code with no success. Providing the definition of the afunc instead declaring it did not help either.

After reading similar questions like Is it possible to friend a class in an anonymous namespace in C++? and GCC doesn't like to make friends with anonymous namespace forward declarations, but MSVC does. What? , I am confused.

Is it impossible/forbidden to declare any thing inside unnamed namespaces as friend or is this just shortcoming of GCC?

If the later case is true, is there any workaround?

AKL
  • 1,367
  • 7
  • 20
  • "is there any workaround?" -> name your namespace? – Nelfeal Jun 25 '23 at 15:42
  • You don't want to do this. Including the class definition in any second translation unit will be an ODR violation because `afunc` in the `friend` declaration will name different entities (as the unnamed namespace member has internal linkage). Either put everything in the unnamed namespace if it is supposed to be local to the translation unit or use a named namespace if external linkage is intended. – user17732522 Jun 25 '23 at 16:13
  • @Nelfeal I need the unnamed namespace to be unnamed because it is within a header library and it contains bunch of helper functions. – AKL Jun 25 '23 at 16:47
  • @user17732522 I need the unnamed namespace to be unnamed because it is within a header library and it contains bunch of helper functions. Also external linkage is not desired for them – AKL Jun 25 '23 at 16:48
  • @AKL And the class definition is not in a shared header? If so, just put it also in an unnamed namespace (it will be the same as the first one). If the class is also in a shared header, then you are not allowed to `friend` an internal linkage function, even if it is syntactically possible. The result will be UB because of an ODR violation. – user17732522 Jun 25 '23 at 17:13
  • @AKL You don't *need* it to be unnamed. You'd like it to be, but you can very much give it a long and specific enough name so that it does not conflict with anything else. – Nelfeal Jun 25 '23 at 17:53

0 Answers0