10

§7.3.1.2/3 in the C++11 Standard (emphasis are mine):

Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal 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) 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. [ Note: The other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules.

Example:

// Assume f and g have not yet been defined.
void h(int);
template <class T> void f2(T);
namespace A {
    class X {
        friend void f(X); // A::f(X) is a friend
        class Y {
            friend void g(); // A::g is a friend
            friend void h(int); // A::h is a friend
            // ::h not considered
           friend void f2<>(int); // ::f2<>(int) is a friend
        };
    };
    // A::f, A::g and A::h are not visible here
    X x;
    void g() { f(x); } // definition of A::g
    void f(X) { /* ... */} // definition of A::f
    void h(int) { /* ... */ } // definition of A::h
    // A::f, A::g and A::h are visible here and known to be friends
}
using A::x;
void h() {
    A::f(x);
    A::X::f(x); // error: f is not a member of A::X
    A::X::Y::g(); // error: g is not a member of A::X::Y
}

Unless I'm missing something, I don't understand the need for the words first above. As far as I can see, you can't have more than one declaration of any entity in a namespace, nor more than one declaration of a friend function in a class.

Also, what is the relevance of the comment "Assume f and g have yet not been defined" in the Example? It really doesn't matter if these functions are declared before the definition of the namespace A. They'll necessarily belong to the global namespace and they'll have nothing to do with the functions declared inside the namespace A.

Edit:

The fact that one can have repeated declarations of the same function, or a declaration and a definition of a function in a namespace, doesn't invalidate my observation that the use of the words first in §7.3.1.2/3 are not necessary.

Edit1

I've just found another error. The comment ::f2<>(int) is a friend is incorrect. Not only there is no definition of the template function f2(T) in namespace A, but more important, the declaration template <class T> void f2(T); must be inside A, otherwise the function f2<>(int) will not be a friend of the class A::X::Y.

Philip Daubmeier
  • 14,584
  • 5
  • 41
  • 77
Wake up Brazil
  • 3,421
  • 12
  • 19
  • 1
    I stand corrected on the reference/declare point. I've retracted my answer. – Angew is no longer proud of SO Apr 15 '14 at 12:18
  • `As far as I can see, you can't have more than one declaration of any entity in a namespace` You can have as many as you like. `namespace N { void foo(); void foo(); void foo(); }` is perfectly valid. Though in this example it's also entirely irrelevant, so that doesn't answer your question. – Lightness Races in Orbit Apr 15 '14 at 12:50
  • On **Edit1**: I don't know what your test to get to that conclusion is, but the example is right in that case. The friend declaration `friend void f2<>(int);` makes `::f2` a friend of the inner type. See [this](http://coliru.stacked-crooked.com/a/28ea111ee638a037) – David Rodríguez - dribeas Apr 15 '14 at 16:46
  • @DavidRodríguez-dribeas Your example is very artificial and it surprises me that it works at all. For instance, this ( http://coliru.stacked-crooked.com/a/e04d9ccf777564d7 ) should compile, but of course it doesn't. Now take a look at a more "normal" example here ( http://coliru.stacked-crooked.com/a/5c97c2f36e21fbf3 ). If the declaration `template void f2(T);` is not inside the namespace, the code doesn't compile, which is exactly what §7.3.1.2/3 mandates. – Wake up Brazil Apr 15 '14 at 17:40
  • Maybe it would be easier to discuss this in a chat. The first link that you provide fails for two reasons: a typo in the function name (`accesss`) and the specialization of `f` not having access to that function (as it is **not** a friend). The second one **does** compile, see it [here](http://coliru.stacked-crooked.com/a/9d3f0f70a67443e3) – David Rodríguez - dribeas Apr 15 '14 at 17:45
  • Created [chat room](http://chat.stackoverflow.com/rooms/50713/discuss-c-7-3-1-2-3) if you are interested in further discussing the code. – David Rodríguez - dribeas Apr 15 '14 at 17:48
  • @DavidRodríguez-dribeas I'm sorry for the "accesss". I got confused with my codes. But here you have the correct version http://coliru.stacked-crooked.com/a/a77d6926ce7ff60b but the second error message strikes me. It doesn't make any sense. – Wake up Brazil Apr 15 '14 at 17:58
  • Why should it? You made the specialization that takes a `Y` a friend, why would the specialization taking a `double` have access? That is by design. If you want to befriend the *whole* template you can do so: `template friend void ::f(T);`. Note that in this case you do need the qualification, and it will still fail to compile as `double` has no member `access`. If you have further questions, it probably makes sense to tackle them in the chat (linked above or [here](http://chat.stackoverflow.com/rooms/50713/discuss-c-7-3-1-2-3)) rather than polluting comments – David Rodríguez - dribeas Apr 15 '14 at 18:04
  • ... also take a look at [this](http://stackoverflow.com/a/4661372/36565) other answer to a previous question that includes the difference between befriending the specialization or the whole template. – David Rodríguez - dribeas Apr 15 '14 at 18:09
  • @DavidRodríguez-dribeas I'm really surprised that this ( http://coliru.stacked-crooked.com/a/9d3f0f70a67443e3 ) works. How come f2() instantiaded in main() can be a friend of A::X::Y ? – Wake up Brazil Apr 15 '14 at 18:10

3 Answers3

4

A hopefully shorter more concise answer than the complete one from Vlad:

An entity can be declared multiple times, your premise is wrong. In the first sentence first is important as these two are valid declarations for a function f in namespace N:

namespace N { void f(); }
void N::f() { ... }        // A definition is *also* a declaration

At this point the need for first in the first sentence is apparent, f is a member of the N namespace (first declaration), not the global namespace.

In the case of a friend declaration the first is important for a different reason, as if the friend declaration is the first declaration, the name is not visible for regular lookup:

//[1]
class Y {};                       // Some type
class X {
   X(Y);                          // allow implicit conversions, 
                                  //    for exposition purposes
   friend X operator+(X, X) {...} // *first* declaration of this operator
};                                //    and also the definition
void f() {
   Y a, b;
   a + b;                         // error, no operator+ takes two Y
   X c; 
   c + b;                         // OK, ADL can find it
}

If the friend declaration was not the first declaration, i.e. if [1] gets replaced with a previous declaration:

class X;
X operator+(X,X);

With all the rest of the code being the same, the above code would compile and call operator+(X,X) converting a and b to X.

The last question you had was on the Assume f and g have not been defined, which I believe should read declared, not defined. The importance of this statement is that if the function have been declared before hand, the comment // A::f, A::g and A::h are not visible here becomes false, as the previous declaration makes those functions visible.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • `The importance of this statement is that if the function have been declared before hand, the comment // A::f, A::g and A::h are not visible here becomes false, as the previous declaration makes those functions visible.` This is wrong. This http://coliru.stacked-crooked.com/a/bb75f21c0469b7e4, nor this http://coliru.stacked-crooked.com/a/1475d2d598e2c223 compile. – Wake up Brazil Apr 15 '14 at 14:14
  • @WakeupBrazil: Your code does not provide a declaration (or definition) of **that** function, but a different function in a different namespace. See [this](http://coliru.stacked-crooked.com/a/e5f783a810e2877d) – David Rodríguez - dribeas Apr 15 '14 at 16:29
  • 1
    +1, I agree that this IMO is the most probable meaning of "first declared in a namespace" – Johannes Schaub - litb Apr 15 '14 at 17:41
3

You are wrong. You may have several declarations of the same function in a declarative region. For example

namespace N
{
   void f( int[10] );
   void f( int[10] );
   void f( int[] );
   void f( int[] );
   void f( int * );
   void f( int * );
}

All these declarations declare the same (and one) function f.

In the quote you cited word first means that a friend function was first declared inside a class definition. There is no function declaration before the declaration inside the class definition.

As for the comment

// Assume f and g have not yet been defined

then it means that the functions were not declared yet. That is their first declarations are inside the class definition.

This part of the quote

Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace

is very clear, Declaring a function as a friend function of a class inside the class definition means its declaration inside the enclosing namespace. However the function is not visible until it will be declared also outside the class definition.

To demonstrate the idea consider the following example.

#include <iostream>

struct A {
    friend void f();
};
void g() { f(); }
void f() { std::cout << "It is me!" << std::endl; }

int main() {
    return 0;
}

For this code the compiler issues error

prog.cpp: In function ‘void g()’: prog.cpp:9:14: error: ‘f’ was not declared in this scope void g() { f(); }

Though function f was declared inside class A definition. And if there is no any declaration of the function before the class definition the function is considered as a member of the same namespace where class A is defined (more precisely it would be better to say where the class is declared because the class can be defined in some enclosing namespace).

However if you add one more declaration of f then the code will be compiled.

#include <iostream>

struct A {
    friend void f();
};

void f();
void g() { f(); }
void f() { std::cout << "It is me!" << std::endl; }

int main() {
    return 0;
}

And consider a third example

#include <iostream>

void f();
namespace N {
   struct A
   {
      friend void f();
   };
   void g() { f(); }
}
void f() { std::cout << "It is me!" << std::endl; }
int main() {
    return 0;
}

Here function f was first declared before namespace N and before the class definition. So the friend declaration of the function f will not be visible in function g() in that namespace until the friend function will be redeclared outside the class. So function g will call the global function f.

And at last consider a more interesting example

#include <iostream>

namespace N {
   class A;
}
class N::A {
    friend void f();
    int x = 10;
};

namespace N {
   //void f(); // if to uncomment the line the code will be compiled 
               // otherwise f will not be found
   void g() { f(); }
   void f() { A a; std::cout << "a.x = " << a.x << std::endl; }
}
int main() {
    return 0;
}

Here though the definition of class A is in the global namespace nevertheless function f is declared in namespace N that is where the class was first declared.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Ok, I was wrong in relation to my first observation. But the words first are still not necessary in the text. – Wake up Brazil Apr 15 '14 at 11:56
  • @Wake up Brazil Again you are wrong. The word first in this context is very important. – Vlad from Moscow Apr 15 '14 at 12:03
  • @Wake up Brazil See my updated post. It explains all. – Vlad from Moscow Apr 15 '14 at 12:16
  • The third example is wrong, it compiles but the following text *"So the friend declaration of the function does not introduce a new name in namescope N"* is false. That friend declaration befriends a function `N::f`, not `::f`. The reason it compiles (and links) is that `N::f` is not visible to `g`, so normal lookup continues outwards and finds `::f`, that is **not** a friend of the type. The function `N::f` is not visible from any context until a later declaration is provided (if any). – David Rodríguez - dribeas Apr 15 '14 at 13:48
  • I have edited the code examples to remove white space. While this is purely stylistic in general, I find that taking less screen real state makes it easier to read on a Q&A web page (I would use more space on a file, with a proper editor and what not, but I feel that this reads better in SO). Feel free to revert some or all of the changes. – David Rodríguez - dribeas Apr 15 '14 at 13:55
  • @David Rodríguez Thanks. It was my mistake. I have updated the post. – Vlad from Moscow Apr 15 '14 at 14:19
  • "Every name first declared in a namespace is a member of that namespace." is not very clear. Apparently it's meant to exclude `int A::b` from being member of the enclosing namespace, but `A::b` is not really "declared" in it. That statement only re-declares a name, and a name of namespace (or class) `A`. A note similar to 3.3.1p4 would be helpful: *"... These restrictions apply to the declarative region into which a name is introduced, which is not necessarily the same as the region in which the declaration occurs."* That note alone shows the subtle potential for confusion. – Johannes Schaub - litb Apr 15 '14 at 17:46
1

Forgive me for omitting the examples, but I want to keep this short and sweet.

The purpose of the word first is to emphasize that the friend or namespace-scope declaration is the only way the function has been declared at that point. The paragraph is intending to discuss declarations that create an entity, as opposed to later matching declarations.

Perhaps initially would be a better word than first.

The comment ::f2<>(int) is a friend is incorrect. Not only there is no definition of the template function f2(T) in namespace A, but more important, the declaration template <class T> void f2(T); must be inside A, otherwise the function f2<>(int) will not be a friend of the class A::X::Y.

::f2 is a different thing than A::f2. The intent of the example is to emphasize this. Because there is a template ::f2, not in A, which matches the friend void f2<>(int) declaration, that template is the one befriended. Only because there is no visible function f matching the declaration friend void f(X); does it by default create a new function in namespace A.

The rule is quite intricate, however. The last sentence before the note means that a function ::f would still not match friend void f(X); because the language prefers to add something to the enclosing namespace, and only looks at outer namespaces as a last resort. So it goes like this:

  1. If the enclosing namespace contains a declaration matching the friend, friend that thing.
  2. Otherwise, if the friend declaration contains sufficient information to declare something in the enclosing namespace, create the thing but don't let the declaration be found by qualified or unqualified lookup.
  3. Otherwise, look for a matching declaration in outer namespaces.
  4. Otherwise, fail.
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • On the last paragraph: It is important to note that lookup is different in the case of a template-id and a regular function. In the case of the template-id (i.e. when finding the template for which `f2<>(int)` is an specialization) lookup will go to outer scopes, but when looking a regular function it will only consider the inner-most namespace. In the example, befriending `f2<>(int)` will move outwards and find the template while befriending `h(int)` won't find the `h` in the global namespace. – David Rodríguez - dribeas Apr 16 '14 at 13:51
  • Other than that, +1 for concisely describing the point of ***first** is to emphasize [...] declaration is the only way the function has been declared at that point* – David Rodríguez - dribeas Apr 16 '14 at 13:52
  • @DavidRodríguez-dribeas Yikes. Yes, I suppose the compiler can't infer a template declaration from a friend declaration of a specialization. – Potatoswatter Apr 16 '14 at 14:25
  • 1
    The difference is really whether the friend declaration can introduce a new entity or has to refer to an existing one. If it can introduce the new entity, it will do so in the immediately enclosing namespace, and it won't attempt to find a previous declaration outside of that scope. If it cannot introduce a new entity, then it must find what it refers to (consider a template specialization, or befriending a member function of a different class) – David Rodríguez - dribeas Apr 16 '14 at 14:40
  • @DavidRodríguez-dribeas Updated along those lines, although I wrote the update before you replied and got distracted before hitting post :P – Potatoswatter Apr 16 '14 at 14:50