I know the general use cases for the friend
keyword with regards to encapsulation but one a couple of occasions, I have needed the friend
keyword just to "get the job done". These use cases don't make me happy so I'm wondering if there are some alternatives. Here's the first minimal example:
struct Foo{
enum class Bar{
a=1,b=2,c=4
};
// need to tell the compiler of operator| before it gets used
// but it can't be a member function of Foo: so add friend keyword
friend Bar operator|(const Bar& b1, const Bar& b2);
// constructor needs a default value using
// operator| for Bars
Foo( Bar b = Bar::a | Bar::b );
};
// definition of operator|, etc.
Is there any way for the compiler to see the declaration of the operator|
for the nested class, inside of interface, before the default values are given at the Foo
constructor declaration?
I also sometimes find myself using the friend
keyword in defining symmetric operations of nested classes within templates. For example:
template<typename T>
struct A{
struct B{
friend bool operator==(const B& x, const B& y) { return true; }
};
};
The operator==
does not require friendship from an encapsulation perspective. But due to operator==
not actually being a templated function and the compiler being unable to deduce the types of nested classes within templates, this seems to be the only reasonable "trick" to keep operator==
as a free function.
As I said, these choices do work, but I'm wondering if there are better choices/practices out there.
friend
gives you an additional benefit, sometimes very important - these function become "hidden" friends. – Creweloperator|()
entirely, is to specifyFoo
s constructor with a default argument in the formFoo( Bar b = Bar(int(Bar::a) | int(Bar::b)))
. Another ways is to add an enum value toBar
nameda_bitor_b = a | b
, and change the default argument ofFoo
s constructor to beFoo(Bar b = Bar::a_bitor_b)
. Then, the declaration of theoperator|()
can be completely outside the definition ofFoo
, as long as you define it consistently (e.g.Foo::Bar operator|(const Foo::Bar &a, const Foo::Bar &b) {...}
– Parous