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.
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 don't understand why the following does not compile (e.g. in gcc 9.10 or MS VS C++ 2019):
class X {
public:
friend bool operator==(int, X const &);
};
int main() {
2 == X(); // ok...
static_cast<bool (*)(int, X const &)>(&operator==); // Error: 'operator==' not defined
return 0;
}
but the following code is compiled without any issues:
class X {
public:
};
bool operator==(int, X const &);
int main() {
2 == X(); // ok...
static_cast<bool (*)(int, X const &)>(&operator==); // OK!
return 0;
}
My expectation is that a friend function (operator==) of X behaves as a standalone function (operator==). What I'm missing? Thanks
What I'm missing?
An inline friend declaration does not make the function available to ordinary name lookup.
Pay close attention to the error. It does not say that the function is of the wrong type, it simply can't find anything named operator==. This is by design.
Inline friend definitions are only found by argument dependent lookup. Ordinary lookup (such as naming the function to take its address), cannot find it. If you want the function to be available for that purpose, you must provide a namespace scoped declaration.
class X {
public:
friend bool operator==(int, X const &) { /* ... */ }
};
bool operator==(int, X const &);
From the standard 11.9.3.7:
Such a function is implicitly an inline ([dcl.inline]) function if it is attached to the global module. 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 ([basic.lookup.unqual]).
From the standard namespace.memdef/3:
(Thanks #StoryTeller)
If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]). [ 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 ] If a friend function or function template 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 ([basic.lookup.argdep]). 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 following doesn't work because the function is not visible in the current scope.
static_cast<bool (*)(int, X const &)>(&operator==); // Error: 'operator==' not defined
The difference is that in the first snippet you only declare the operator in the scope of X, but not outside. There is no operator==(int,X const &) accesible from main. If you fix that and do declare it also outside you only get warnings:
class X {
public:
friend bool operator==(int, X const &);
};
bool operator==(int,X const&); // <--
int main() {
2 == X(); // ok...
static_cast<bool (*)(int, X const &)>(&operator==); // Error: 'operator==' not defined
return 0;
}
Note however, that for both cases you do need a definition to actually call the operator.
For illustration consider that with
struct foo {
friend void bar() {
std::cout << "this is a inline definition of friend funtion";
}
};
The only way to access bar from outside foo is to add a declaration outside of foo:
void bar();
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.
Nonmember functions that are part of the interface of a class should be declared in the same header as the class itself.
The upper quote came from the book C++Primer 5th ed. I wonder if there is a best practice to distinguish nonmember functions and member functions in the header file? Or this is not necessary at all?
Or put it this way:
As a designer of a class, is it necessary to tell the user in the header file that which function is only part of the interface and which one is member function?
The language syntax already distinguishes members from non members, both for definition and declaration.
Declarations
class Example
{
public:
void member(int); // member, inside the class definition
friend std::istream & operator>>(std::istream &, Example &); // non-member, marked with keyword friend
}
std::ostream & operator<<(std::ostream &, Example &); // non-member, outside the class definition
Definitions
void Example::member(int param) {} // Example:: qualification on the name
std::istream & operator>>(std::istream & is, Example &) { return is; } // no Example::
std::ostream & operator<<(std::ostream & os, Example &) { return os; } // no Example::
You can often lay the header out in sections, and give the group a heading, but the distinction is apparent from the syntax