Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

friendship with extern "C" function seems to require :: to qualify name

Tags:

c++

extern

friend

Trying to make a class friends with an extern "C" function, this code works:

#include <iostream>

extern "C" {
  void foo();
}

namespace {
  struct bar {
    // without :: this refuses to compile
    friend void ::foo();
    bar() : v(666) {}
  private:
    int v;
  } inst;
}

int main() {
  foo();
}

extern "C" {
  void foo() {
    std::cout << inst.v << std::endl;
  }
}

But I was very surprised to find that with g++ 4.6.1 and 4.4.4 I have to explicitly write :: in friend void ::foo(); otherwise the friendship doesn't work. This :: is only needed when it's extern "C" though.

  1. Is this a compiler bug/problem? I wasn't expecting that behaviour.
  2. If it isn't a bug why is this required, but only when it's extern "C" and not without it? What about the name lookup rules changes that makes this necessary?

I'm stumped. There is probably some rule for this that I can't find.

like image 282
Flexo Avatar asked Oct 18 '11 15:10

Flexo


People also ask

How do you declare a friend function outside the class?

Syntax of friend functions: To make a function that is declared outside the class “friendly” to that class, we have to declare the function as a friend function, as seen below: class className{ // Other Declarations friend returnType functionName(arg list); };

How do you declare a friend function in C++?

The friend function is declared using the friend keyword inside the body of the class. Friend Function Syntax: class className { ... .. ... friend returnType functionName(arguments); ... .. ... }

What does friend keyword do in C++?

friend is a keyword in C++ that is used to share the information of a class that was previously hidden. For example, the private members of a class are hidden from every other class and cannot be modified except through getters or setters.

Is there friend function in C?

Master C and Embedded C Programming- Learn as you goA friend function of a class is defined outside that class' scope but it has the right to access all private and protected members of the class. Even though the prototypes for friend functions appear in the class definition, friends are not member functions.


1 Answers

[n3290: 7.3.1.2/3]: Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) 95) this implies that the name of the class or function is unqualified. until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace. [..]

The innermost enclosing namespace is the anonymous one, and you didn't qualify the function name, so the name is not found.

The namespace need not be anonymous, either.

Note that the extern "C" in the question is a red herring, as the following also fails for the same reason:

void foo();

namespace {
struct T {
   friend void foo();

   private: void bar() { cout << "!"; }
} t;
}

void foo() { t.bar(); }

int main() {
   foo();
}

/*
In function 'void foo()':
Line 7: error: 'void<unnamed>::T::bar()' is private
compilation terminated due to -Wfatal-errors.
*/

[alternative testcase, adapted from your original code]

like image 60
Lightness Races in Orbit Avatar answered Oct 05 '22 04:10

Lightness Races in Orbit