In his recent blog post Anthony Williams talks about hidden friends. The main idea, if I understood it correctly, is that functions declared as friends cannot be found by ADL in certain situations. Simple example:
namespace N {
struct A {
friend void foo(A) { }
};
struct B {
operator A();
};
// (*)
void bar(A) { }
}
void func() {
N::A a;
bar(a); // OK, bar is found via ADL
foo(a); // OK, foo is found via ADL
N::B b;
bar(b); // OK, bar is found via ADL
foo(b); // NOT OK, foo cannot be found
}
In all examples in the blog post, the friend functions are defined inside classes. Is it possible to declare a friend function and then define it later at the point (*), so that it remains hidden? It looks like hidden friends can only be defined in the class scope (or in another compilation unit).
Hidden friends need to be fully defined inline, i.e., inside of the definition of class. Yes, if you define friends somewhere else, where definition can cause namespace visibility, it would break restrictions based on hidden friends to be found as match by ADL search only, and as such be candidate for overload resolution.
Further more in WG21 recommendations for specifying hidden friends,
is noted that hidden friends are fully defined inline, like in this snippet:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
Hidden friends can be defined out of line, but then they are not hidden in that TU. As an example, consider this header:
class A {
// this is hidden friend defined inline
friend int operator+(A, int) { return 0; }
// this is hidden friend defined out of line
friend int operator+(int, A);
// not a hidden friend (see below)
friend int operator+(A, A);
};
int operator+(A, A); // this is no longer hidden friend in any TU
and then a separate cpp file:
#include "a.hpp"
// This is not a hidden friend in this TU, but is in other TUs.
int A::operator+(int, A) {
return 2;
}
Doing this is useful when you have operators/ADL customization points that depend on other large headers for their implementation.
Related
I've just started learning templates in C++ and for practice purposes wrote this simple code
#include <iostream>
template<typename T>
class A;
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x);
template <typename T>
class A
{
T m_x = 10;
public:
A(T x) : m_x{ x } {}
friend std::ostream& operator<< <T>(std::ostream& out, A x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x)
{
out << "m_x = " << x.m_x;
return out;
}
int main()
{
A<int> a1{ 10 };
std::cout << a1 << '\n';
}
It works as expected, that is I get 10 as the output, but there is one thing that bothers me. At which point is the operator<< function instantiated? Does it happen at the point of creation of the a1 object (this is also the point where A<int> is implicitly instatiated, right?) or does it happen when I call the operator<< in std::cout << a1 << '\n'? My guess is that the second option is correct and I base it on this excerpt from cppreference which says that:
When code refers to a function in context that requires the function definition to exist, or if the existence of the definition affects the semantics of the program (since C++11), and this particular function has not been explicitly instantiated, implicit instantiation occurs.
But is it true that a friend declaration does not require the function definition to exist?
I'm sorry if this question is ill-pharased, I did my best to use the nomenclature right, but I'm just a beginner.
EDIT
What about this?
template <typename T>
class foo
{
T m_x;
friend void bar(foo x)
{
x.m_x = "123";
}
};
if I put a friend function definition inside a class, every instantiation of that class causes a new, ordinary function overload to be created that takes an argument of the current specialization, hence I would expect to see an error as soon as I write this: foo<int> x; but I don't get one... (for example, bar(x); causes the error)
I am not a language lawyer, so I'll try to answer with examples.
There are two aspects. First friend declaration.
A friend delcaration is a declaration. For example:
struct foo {
friend void bar();
};
int main() {
foo f;
}
Compiles and executes without any problem.
friend void bar(); declares a function bar. This functions is never defined. As long as we do not call it, thats not an issue. Of course, typically you would provide a definition, but if the function is never called you do not necessarily need to define it. Actually there are situations where having a declaration but no definition is on purpose, though thats out of scope of the quesiton.
Next, is templates and the question when member functions are instantiated. For that, consider this example:
#include <iostream>
template <typename T>
struct foo {
void bar() {
T x = "123";
}
};
int main() {
foo<int> x;
//x.bar();// error!
}
Compiles and executes without any problem.
Initializing an int with the string literal "123" is of course non-sense. Its only to provoke a compiler error when the method is instantiated. We can create an object of foo<int>. Though, we cannot call foo<int>::bar, because its not valid.
You can find many examples of methods of class templates that can only conditionally be instantiated in the standard library. For example std::map<key_t,value_t>::operator[]. It requires value_t to be default constructible, because it potentially has to default construct a value_t. You can use a std::map with a non-default-constructible value_t, you just cannot call its operator[]:
#include <map>
struct foo {
foo(int){}
};
int main() {
std::map<int,foo> x; // completely fine
x[1] = foo(1); // error
}
I spare you the complete error message. It is horrible, the essential part is:
error: no matching function for call to 'foo::foo()'
The overload of the operator<< in your case gives you an individual overload to every template classA<T>, so I can assume, that instantiation of operator<< can be with every instantiation of your class A<T>.
You can checkout this post, it can be useful in your case.
When I have a small piece of code like this:
#include <iostream>
class A {
public:
friend inline std::ostream& operator<<(std::ostream& os, const A&);
};
inline std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
the operator<< is called twice for both a and b, because b has an implicit user conversion operator for type A. But I was surprised when I modified the code to this:
#include <iostream>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
};
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
As you see, I have just transferred the definition inside the class rather than using a free function and marking it as a friend of the class. But this code gives an error which says no suitable function for operator<< is found for b.
Why does this problem happen?
It comes down to how C++ generates candidate functions when performing overload resolution. It's trying to find candidates for operator<<(std::cout, b). This means it performs unqualified name lookup which includes performing argument-dependent lookup (ADL). Let's take a look at how that works.
For the first code snippet, unqualified name lookup finds the declaration when it looks in the enclosing scope of the calling code, without needing to perform ADL. It sees inline std::ostream& operator<<(std::ostream& os, const A&) as a candidate, and then is able to apply the user-defined conversion to b to see that it's a valid function to use for overload resolution. All well and good.
For the second code snippet, though, we don't have a declaration of operator<< at file scope. The declaration and definition are entirely within the definition of the class A. That still might let us find it as a candidate function for std::cout << b, but it'll have to be through ADL. Let's check to see if it's actually visible through that:
Otherwise, for every argument in a function call expression its type
is examined to determine the associated set of namespaces and classes
that it will add to the lookup.
...
For arguments of class type (including union),
the set consists of
a) The class itself
b) All of its direct and indirect base classes
c) If the class is a member of another class, the class of which it is a member
d) The innermost enclosing namespaces of the classes added to the set
At any stage, would we look inside the definition of A when performing ADL with arguments std::cout and b? None of a), b), and c) apply to A because A isn't B, A isn't a base class of B, and A doesn't contain B as a member. Crucially, "any class to which the class is implicitly convertible" isn't used to generate candidates through ADL.
So ultimately in the second code snippet, the name lookup never sees the declaration of std::ostream& operator<<(std::ostream& os, const A&) and never realizes that it can apply a user-defined conversion to apply it with the appropriate arguments.
If we just make the function declaration (not definition) visible at file scope like so:
#include <iostream>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
};
std::ostream& operator<<(std::ostream& os, const A&);
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
This function declaration is once again found through ordinary unqualified name lookup, the user-defined conversion comes in during overload resolution, and the expected output of "Called" being printed twice is recovered.
because you use friend only if you want access to the members of the class but still they need to defined as a global function and then make them friend function of the class.
I have the following code:
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
Live example
Both g++4.8 and clang3.4 fail to compile it, because f is not visible inside M, or so they say.
However, the Standard gives an example of a similar code
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
and says that
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
(ISO/IEC 14882:2011 11.3 Friends [class.friend] p6, p7)
From this I can't understand how compiler can't find f which is defined in same class where it's used.
It's kinda unlikely that both compilers have the same bug.
So, what did I miss?
The friend declaration states that a function called f in the surrounding namespace is a friend of the class; but it does not introduce the name f into the namespace. It's not available (except by argument-dependent lookup) until it's been declared in the namespace.
The relevant rule is C++11 7.3.1.2/3:
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 or by qualified lookup until a matching declaration is provided in that namespace scope.
This quote from the C++ Standard
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
means the following
9 Name lookup for a name used in the definition of a friend function
(11.3) defined inline in the class granting friendship shall proceed
as described for lookup in member function definitions.
That is any name used in the function is searched starting from the class scope.
However the function itself is not visible in the namespace until it will be declared outside the class.
So in your case it is enough to declare the function before the class definition
void f() {}
struct M {
friend void f();
M() {
f();
}
};
int main() {
M m;
}
Or
void f();
struct M {
friend void f() {}
M() {
f();
}
};
int main() {
M m;
}
The critical question is under what circumstances is the compiler able/allowed to find your function declaration.
For a general friend function, you have to declare it outside of the class such that the compiler is able to find it.
However there is a very useful exception: If the the friend function has an argument of class type, it is able to find the function without additional declaration due to argument-dependent name lookup.
This case is actually very important because normally you would want a friend function to access an object of class type.
Consider the following example:
#include <iostream>
struct M
{
friend void printI(int a) {
std::cout << a;
}
friend void print(const M& m) { // friend takes object of class type!
std::cout << "M";
}
void foo() {
printI(2); // ERROR - requires declaration!
print(*this); // OK!
}
};
int main()
{
M m;
m.foo();
printI(2); // ERROR - requires declaration!
print(m); // OK
}
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
The above code works perfectly.(tried on DevC++)
Also try not to define the function inside the class as it might not have a scope outside it i.e. in main().
In trying to call f() from main() you'll receive an error saying function doesn't exist.
Therefore, define function outside classes using :: operator (if necessary) so that there is no problem accessing the function from anywhere.
Access friend function defined in class
G'day!
I have a question around the use of friend in C++. Consider the following piece of code:
#include <ostream>
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const N&);
friend std::ostream& operator<< (std::ostream&, const F&);
};
void foo(std::ostream &out) {
F bar;
out << bar;
}
My understanding always was, that friend is similar to static with the additional property that the friend function has access to the private part of the class. Under that assumption, the code should compile, since there is an operator<< that takes an ostream& and a (const) F&.
It appears that g++ 4.0 shares my thoughts on this, as it accepts that code. The much newer g++ 4.5(.2) however, rejects the code with the message:
ns.cc: In function 'void foo(std::ostream&)':
ns.cc:14:10: error: no match for 'operator<<' in 'out << bar'
is g++ 4.5 wrong or am I (and g++ 4.0) wrong?
(The solution to move the friend declaration into the F class doesn't help, as the operator<< will need access to the private part of N.)
Regards,
Stefan
The problem is that a friend declaration doesn't provide a global function declaration, unless you provide an inline implementation.
struct N {
friend void func1() { }
friend void func2();
friend void func3();
};
void func3();
func1(); /* OK */
func2(); /* not OK */
func3(); /* OK */
You have to declare the operators outside the struct as well. Same error is reported by gcc 4.4.
#include <ostream>
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const N&);
friend std::ostream& operator<< (std::ostream&, const F&);
};
std::ostream& operator<< (std::ostream&, const N&);
std::ostream& operator<< (std::ostream&, const F&);
void foo(std::ostream &out) {
F bar;
out << bar;
}
I've been trudging through the standard (FCD, n3242) since I saw the question
In [class.friend] one can read:
6) A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope.
7) Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).
9) A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.
So, what happens here ?
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const F&);
};
The friend declaration nominates this overload of operator<< to be a friend of N. However this overload has not been declared in a lexical scope (either namespace or class). Also, 7 does not apply because it is not defined within N either.
Therefore, when looking up the overloads of operator<< that can apply in:
void foo(std::ostream &out) {
F bar;
out << bar;
}
There is no valid overload (actually, it could be there is no overload at all).
You have two solutions:
use 7: define the function inline following the friend declaration.
use 9: declare the function in the namespace too
Because of 4 though:
4) A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).
I would recommend declaring it prior to the friend declaration to control its linkage, but it will rarely matters.
Suppose I have a class F that should be friend to the classes G (in the global namespace) and C (in namespace A).
to be friend to A::C, F must be forward declared.
to be friend to G, no forward declaration of F is necessary.
likewise, a class A::BF can be friend to A::C without forward declaration
The following code illustrates this and compiles with GCC 4.5, VC++ 10 and at least with one other compiler.
class G {
friend class F;
int g;
};
// without this forward declaration, F can't be friend to A::C
class F;
namespace A {
class C {
friend class ::F;
friend class BF;
int c;
};
class BF {
public:
BF() { c.c = 2; }
private:
C c;
};
} // namespace A
class F {
public:
F() { g.g = 3; c.c = 2; }
private:
G g;
A::C c;
};
int main()
{
F f;
}
To me this seems inconsistent. Is there a reason for this or is it just a design decision of the standard?
C++ Standard ISO/IEC 14882:2003(E)
7.3.1.2 Namespace member definitions
Paragraph 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
(this implies that the name of the class or function is unqualified) the friend class
or function is a member of the
innermost enclosing namespace.
// 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
}
Your friend class BF; is a declaration of A::BF in namespace A rather than global namespace. You need the global prior declaration to avoid this new declaration.
Let's take into account these 3 code lines from your sample:
1. friend class F; // it creates "friend declaration", (that's not the same as ordinary forward declaration
2. class F; // without this forward declaration, F can't be friend to A::C <-- this is ordinary forward declaration
3. friend class ::F; // this is qualified lookup (because of ::), so it needs previous declaration, which you provide in line 2.
C++ standard in paragraph 7.3.1.2, point 3 ( Namespace member definitions) says:
The friend declaration does not by itself make the name visible to
unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The
name of the friend will be visible in its namespace if a matching
declaration is provided at namespace scope (either before or after the
class definition granting friendship). —end note ]
And line 2 follows exactly what standard requires.
All confusion is because "friend declaration" is weak, you need to provide solid forward declaration for further usage.
Because it wouldn't make sense to be able to declare something in the global namespace if you're inside a namespace {} block. The reason friend class BF; works is that it acts like an implicit forward declaration.