I'm still a beginner in C++ trying to learn more about the language. I recently read about the concept of ADL (Argument-Dependent Lookup) and Hidden Friends idiom (https://www.modernescpp.com/index.php/argument-dependent-lookup-and-hidden-friends). My understanding of ADL is that in the case of an unqualified function call, C++ looks for the function in not only the current namespace, but also the namespace of the argument type.
I'm confused at what the point of the hidden friend idiom is, and what hidden friend means exactly (i.e. what is hidden about it). I get that friend functions of a class are non-member functions but can access private members of the class. However, I don't see why they are necessary. In the code example given in the reading, it points out the necessity of friends in the given functions specifically for general overloads with two parameters of a custom class. That is, in
class MyDistance{
public:
explicit MyDistance(double i):m(i){}
MyDistance operator +(const MyDistance& a, const MyDistance& b){
return MyDistance(a.m + b.m);
}
friend MyDistance operator -(const MyDistance& a, const MyDistance& b){
return MyDistance(a.m - b.m);
}
friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){
out << myDist.m << " m";
return out;
}
private:
double m;
};
The + operator overload for the class is not a friend, is a member function, and technically takes in 3 parameters of MyDistance
here I believe since it is a member function (this) and takes 2 additional parameters, making it invalid.
However, instead of having a hidden friend, couldn't we just write the code as
class MyDistance{
public:
...
MyDistance operator +(const MyDistance& other){
return MyDistance(m + other.m);
}
...
};
Is there any downside to writing the code like this? Is it slower (at compile time) in some way due to the order in which C++ does the lookup (perhaps looking at non-member functions before looking at member functions)? Also, what exactly is the "hidden friend idiom" supposed to "hide"? Is it that the function itself is defined in the class instead of outside?
Is there any downside? Yes, in your example above C++ applies different rules to the two arguments of operator+. Specifically the left hand argument must be an object of type MyDistance
but the right hand argument can be any type convertible to MyDistance
.
Extending your example a little
class MyDistance{
public:
...
MyDistance(int dist) { ... }
MyDistance operator+(const MyDistance& other) const {
return MyDistance(m + other.m);
}
...
};
With this code
MyDistance x(1);
MyDistance y = x + 2;
is legal because there is a conversion from int
to MyDistance
but this is illegal
MyDistance x(1);
MyDistance y = 2 + x;
because given the declaration above the left hand side of +
must be a MyDistance
object.
There is no such problem when operator+
is a friend, in that case either argument can be convertible to MyDistance
and both versions of the code above are legal.
Our expectation of operator+
is that it is symmetric, so the friend version is better because it applies the same rules to both arguments.