the following code compiles fine under gcc:
class vec3
{
private:
float data[3];
public:
vec3(float x, float y, float z)
{
data[0] = x;
data[1] = y;
data[2] = z;
}
void operator =(const vec3 &v)
{
data[0] = v.data[0];
data[1] = v.data[1];
data[2] = v.data[2];
}
friend vec3 operator *(float a, const vec3 &v)
{
vec3 res(v.data[0], v.data[1], v.data[2]);
res.data[0] *= a;
res.data[1] *= a;
res.data[2] *= a;
return res;
}
};
int main(int argc, char **argv)
{
vec3 v(1.0, 2.0, 3.0);
vec3 u = 2*v;
return 0;
}
it seems tho the operator * is defined within the class it is compiled as a non-member function because it is declared as friend. is this the standard behaviour? it seems a bit of an odd way to define a non-member function, I haven't seen this way of defining non-member friends in any text-books/faqs (normally declared within the class and defined outside).
james
It's standard and very useful. Even if friendship isn't needed (i.e. only streaming public values), I often define inside some class "X":
friend std::ostream& operator<<(std::ostream& os, const X& x)
{
return os << x.a << " & " << x.b;
}
In your example, the operator* needs to be a friend to access data, but needs to be a non-member as the lhs value is not an instance of the class. Don't be confused by the fact it's defined - as distinct from only declared - inside the class. That doesn't change anything except that the function is implicitly as if "inline" qualified (which is only a compiler hint and doesn't guarantee inlining), avoiding issues with the one-definition rule during multiple inclusions.
Yes..
According to the standard docs, 11.4 Friends - 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.
Example:
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
Note that the function name is unqualified and it is a global function which has the scope of the associated namespace in where it is defined..
It is standard behavior, and I've seen it at least once in Effective C++.
Related
Why does defining user defined literal inside the class give error?
class test
{
long double x;
public:
friend test operator""_UNIT(long double v)
{
test t;
t.x = v;
return t;
}
};
int main()
{
test T = 10.0_UNIT;
return 0;
}
ERROR:
unable to find numeric literal operator 'operator""_UNIT'
Note: It is possible to define any friend function inside the class.
class test
{
int x;
public:
test():x(10) {}
friend std::ostream& operator<< (std::ostream& o, test t)
{
o << t.x ;
return o;
}
};
int main() {
test T;
std::cout << T;
return 0;
}
The same friend user defined literal can be defined outside the class.
class test
{
long double x;
public:
friend test operator""_UNIT(long double v);
};
test operator""_UNIT(long double v)
{
test t;
t.x = v;
return t;
}
int main()
{
test T = 10.0_UNIT;
return 0;
}
Does this quote from the standard have an impact?
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
The issue you're running into is that, from [namespace.memdef]:
The friend declaration does not by
itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3).
The way they are found is through argument dependent lookup, [basic.lookup.argdep]:
When considering an associated namespace, the lookup is the same as the lookup performed when the
associated namespace is used as a qualifier (3.4.3.2) except that: [...] Any namespace-scope friend functions or friend function templates declared in associated classes are
visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3).
std::ostream& operator<< (std::ostream& o, test t) is found due to argument-dependent lookup on the second argument.
When you define _UNIT externally to the class, it makes the function visible.
However, when you define _UNIT inline - it's not visible to normal lookup and the only argument (double) does not have any associated namespaces so there's no way for it to be found with argument-dependent lookup either.
As described here C++11 style SFINAE and function visibility on template instantiation class member functions overshadow free functions. Using a fully qualified name usually works, however I am having a hard time with friend functions of other classes which are declared in-line. Consider the following example:
namespace N {
struct C {
friend int f(const C& c) {
return 1;
}
friend int g(const C& c) {
return 2;
}
};
struct D {
void f() {
g(C{}); // ADL finds this
::N::f(C{}); // not found dispite full qualification
}
};
}
I think I understand what the problem is, as described here What's the scope of inline friend functions? inline friend function are usually found using ADL and not really visible in the enclosing namespace.
So my question is how should I change my code to make this work (aside from renaming one of the f's)?
It's because of the friendliness:
[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 simple name lookup until a matching declaration is provided in that namespace scope [...]. If a friend function is called, its name may be found by the name lookup that considers function from namespaces and classes associated with the types of the function arguments (3.4.2) [i.e. ADL].
The fix is to simply provide that declaration:
namespace N {
struct C {
friend int f(const C& c) {
return 1;
}
friend int g(const C& c) {
return 2;
}
};
int f(const C& c);
int g(const C& c);
struct D {
void f() {
g(C{});
::N::f(C{});
}
};
}
(live demo)
I'm currently reading "Effective C++" and there is a chapter that contains code similiar to this:
template <typename T>
class Num {
public:
Num(int n) { ... }
};
template <typename T>
Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... }
Num<int> n = 5 * Num<int>(10);
The book says that this won't work (and indeed it doesn't) because you can't expect the compiler to use implicit typecasting to specialize a template.
As a soluting it is suggested to use the "friend" syntax to define the function inside the class.
//It works
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
Num operator*(const Num& lhs, const Num& rhs) { ... }
};
Num<int> n = 5 * Num<int>(10);
And the book suggests to use this friend-declaration thing whenever I need implicit conversion to a template class type. And it all seems to make sense.
But why can't I get the same example working with a common function, not an operator?
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
void doFoo(const Num& lhs) { ... }
};
doFoo(5);
This time the compiler complaints that he can't find any 'doFoo' at all.
And if i declare the doFoo outside the class, i get the reasonable mismatched types error. Seems like the "friend ..." part is just being ignored.
So is there a problem with my understanding? What is the difference between a function and an operator in this case?
The reason is that here
doFoo(5);
the compiler has no way of finding foo, given an int parameter. This would be the equivalent of calling your friend operator like this:
Num<int> n = 5 * 10;
This will "work", but not by calling the friend operator* defined in your Num class, but by calling the built-in operator* for integers, and then using the implicit conversion from Num's converting constructor.
The core problem is lookup. A friend declaration provides a declaration of a namespace level function, but the declaration is only available inside the class that is befriending it. In the example the book provides that is not an issue: the function takes two arguments of the enclosing type, as long as one of them is of the enclosing type, Argument Dependent Lookup will look inside the definition of the class and find the operator. In your case that is not the case, since there is a single argument and that needs a conversion, the compiler will not look inside the definition of the class.
Note that this is regardless of templates and conversions:
class A {
friend void f( int ) {}
friend void g( int, A ) {}
};
int main() {
f(5); // Error: lookup cannot find 'f' declared *only* inside A
g(5,A()); // Ok, one argument is 'A', lookup will find the function
}
In the case above, where there are no templates involved, you could potentially add a declaration at namespace level to fix it, but that is not really an option for template classes.
class A {
friend void f() { std::cout << "inside A\n"; }
};
void f(int); // only declaration
int main() {
f(5); // "inside A"
}
This cannot be done for a template (and for all instantiating types) as the friend declaration is a declaration of a non-templated function. Although you could can play with the code just for the sake of testing:
template <typename T>
struct Num {
Num(int x) ...
friend void f( Num const & );
};
Num<int> f(Num<int> const &); // only declaration
int main() {
f(5);
}
Yes these code compiler do not know how to work with it .
like
doFoo(5)
compiler do not know 5 is int
I understand how polymorphism and inheritance works in C++, but my problem is: how do you make operators polymorphic for the following specific example?
Say I have a Foo class and two Foo instances, fooA and fooB. I want to redefine the plus sign operator so that "fooA + fooB;" does something specific to Foo instances (whatever that may be). How would the function prototype look? It's confusing me because I'm used to functions starting with a letter... Any help would be greatly appreciated.
By the way, this isn't a homework question -- more like a wonderment (I was thinking about polymorphism in Ruby).
Example from http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/cplr318.htm:
#include <iostream>
using namespace std;
class complx
{
double real, imag;
public:
complx(double real = 0., double imag = 0.); // constructor
complx operator+(const complx&) const; // operator+()
};
// define constructor
complx::complx(double r, double i)
{
real = r; imag = i;
}
// define overloaded + (plus) operator
complx complx::operator+(const complx& c) const
{
complx result;
result.real = this->real + c.real;
result.imag = this->imag + c.imag;
return result;
}
int main()
{
complx x(4,4);
complx y(6,6);
complx z = x + y; // calls complx::operator+()
}
const Foo operator+(const Foo& a, const Foo& b) is the correct signature. It will need to be a friend function if the data is private and has no mutator functions (that is, "setters").
Operators should be global functions instead of members in order for the the first parameter to be coerced to your type. For example, if int can be coerced to Foo, this is legal with the above signature: 1 + foo.
Edit:
Code demonstrating why operator+ should be global...
struct Foo {
int i;
Foo(int i) : i(i) {}
const Foo operator+(const Foo& a) {
return Foo(this->i + a.i);
}
};
int main() {
Foo f(5);
f + 1;
1 + f; // g++ 4.5 gacks here.
return 0;
}
Here's the error:
main.cpp: In function ‘int main()’:
main.cpp:14:9: error: no match for ‘operator+’ in ‘1 + f’
For binary +, you need some form of double dispatch, which isn't
supported out of the box by C++. There are several ways of implementing
this, all with various disadvantages. And regardless of how you
implement the double dispatch itself, for n different derived types,
you will need n2 different functions.
I got this example from my book, but I have no idea how to actually call the ticket function. This is the code:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
I get the "candidate function(s) not accessible" error message.
A few points will help you figure out what's going on here:
I) Friend function definitions within classes can only be found by Argument dependent lookup when called from outside the class definition.
II) Function templates that are supplied explicit template arguments do not undergo ADL unless the compiler is given some explicit help in identifying the call as a function call.
III) Argument dependent lookup (ADL) only works for user defined types.
A few examples will better illustrate each of the above points:
//------------------------
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
};
S s;
int i = f(3); // error - ADL does not work for ints, (III)
int j = f(s); // ok - ADL works for UDTs and helps find friend function - calls 2 (III)
// so how do we call function 1? If the compiler won't find the name via ADL
// declare the function in the namespace scope (since that is where the friend function
// gets injected)
int f(int); // This function declaration refers to the same function as #1
int k = f(3); // ok - but not because of ADL
// ok now lets add some friend templates and make this interesting
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
template<class T> friend int g(int) { return 0; } // 3
template<class T> friend int g(S) { return 0; } // 4
template<class T> friend int g() { return 0; } // 5
};
S s;
int k = g(5); // error - no ADL (III)
int l = g(s); // ok - ADL - calls 4
int m = g<int>(s); // should call 4 - but no ADL (point II above)
// ok so point II above says we have to give the compiler some help here
// We have to tell the compiler that g<int> identifies a function
// The way to do that is to add a visible dummy template function declaration
template<class /*Dummy*/, class /*TriggerADL*/> void g();
int m = g<int>(s); // ok - compiler recognizes fun call, ADL triggered - calls 4
int n = g<int>(3); // still not ok - no ADL for ints
// so how do we call either function 3 or 5 since we cannot rely on ADL?
// Remember friend functions are injected into the outer namespace
// so lets just declare the functions in the outer namespace (as we did above)
// both these declarations of g below refer to their counterparts defined in S
template<class T> int g(int);
template<class T> int g();
int o = g<int>(3); // ok
int p = g<int>(); // ok
// Of course once you have these two declarations at namespace scope
// you can get rid of the Dummy, TriggerADL declaration.
Ok so now lets return to the Vandevoorde example that you quoted, and now this should be easy:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter;
template<class T> int ticket(); // <-- this should work with a conformant compiler
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Hope that helps :)
Hotfix
There is a hot-fix available, but read the below explanation if you want to understand what's going on.
#include <iostream>
template<typename T> int ticket();
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter; // don't forget the definition
int main() {
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
As the snippet shows, you have to declare the template to make it visible when you call it.
Friend function definitions
This is confusing, since there are some rules in the way in this case. Some basic points, and then some other points.
struct A {
friend void f(A*) { std::cout << "hello"; }
};
What does it do? It defines a friend function. Such a function is a member of the enclosing namespace. It's not a class member, even though it is defined within a class! The fact that it's defined within a class only changes the lexical scope of that function: It can refer to that class' members directly, without preceding the class-name.
Most importantly, though, the function is not visible after being declared. You cannot take its address doing something like this, for example
&f
The only way that the function would work is using argument dependent lookup. A lookup that ends up having that class as its associated class will consider that friend function. That means that the following works:
f((A*)0);
It works because the call includes an argument with type that has the class included. In that case, the class is an associated class, and the friend declaration will be considered.
The following won't work, for example
f(0);
Because it has no idea that it should look within A to find a friend declaration. A friend function definition of a function without an argument won't be found, because there is no argument dependent lookup happening, then.
Friend function definition for templates
In addition to the fact that your call does not include arguments, it has another problem. If you define a friend function template, the matter is more complicated. There is a rule that says that if the compiler sees T<A1, A2, A3>, that this only refers to a template specialization if T actually resolves to a template. Consider
ticket < int > ()
The compiler can't resolve ticket, because it is not visible to normal lookup. Therefor, the rule says that ticket<int> does not refer to a function. It has to be parsed as a relational expression, yielding to the following
(ticket < int) > ()
That will be a syntax error, because int is not a value, and () is neither a value.
Example
Here is an example where it matters.
struct A {
template<int I> friend void f(A*) { }
};
// try to comment this out
template<typename Dummy> void f();
int main() {
f<1>((A*)0);
}
That compiles. It compiles because f resolves to a template (although a completely different one that can't even accept a non-type template argument - but that doesn't matter!). But a Standard conforming compiler will not compile the snippet once you comment out the second declaration, because it's compiled as a relational expression (less-than and smaller-than) and it will not find symbol f.
Read this thread for further information: What am I missing in this template toy example?.
I do get the same error using the MS VS++ compiler. According to the docs on MSDN:
http://msdn.microsoft.com/en-us/library/h2x4fzdz(VS.80).aspx
Friends are not in the class's scope,
and they are not called using the
member-selection operators (. and –>)
unless they are members of another
class. A friend function is declared
by the class that is granting access.
So friend functions are not actually part of the class and should therefore not be defined in class scope. Define the function outside of the class:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket();
static int counter;
};
template<typename T>
int ticket() {
return ++Manager::counter;
}
int Manager::counter;
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Why not make it static instead?
#include <iostream>
class Manager {
public:
template<typename T>
static int ticket()
{
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << Manager::ticket<int>() << std::endl;
}
Though really, it doesn't have to be a template either. I assume you needed information specifically about friend templates?