usos no convencionales de friend en c++
Conozco los casos de uso generales para la palabra clave friend
en relación con la encapsulación, pero en un par de ocasiones he necesitado la palabra clave friend
solo para “hacer el trabajo”. Estos casos de uso no me hacen feliz, por lo que me pregunto si existen algunas alternativas. Aquí está el primer ejemplo mínimo:
struct Foo{
enum class Bar{
a=1,b=2,c=4
};
// necesito decirle al compilador acerca del operator| antes de que se use
// pero no puede ser una función miembro de Foo: así que agregamos la palabra clave friend
friend Bar operator|(const Bar& b1, const Bar& b2);
// el constructor necesita un valor predeterminado utilizando
// operator| para Bars
Foo( Bar b = Bar::a | Bar::b );
};
// definición de operator|, etc.
¿Hay alguna manera de que el compilador vea la declaración del operator|
para la clase anidada, dentro de la interfaz, antes de que se den los valores predeterminados en la declaración del constructor de Foo
?
También a veces me encuentro usando la palabra clave friend
para definir operaciones simétricas de clases anidadas dentro de plantillas. Por ejemplo:
template<typename T>
struct A{
struct B{
friend bool operator==(const B& x, const B& y) { return true; }
};
};
El operator==
no requiere amistad desde una perspectiva de encapsulación. Pero debido a que operator==
no es realmente una función de plantilla y el compilador no puede deducir los tipos de las clases anidadas dentro de las plantillas, parece ser el único “truco” razonable para mantener operator==
como una función libre.
Como dije, estas opciones funcionan, pero me pregunto si existen mejores opciones/prácticas disponibles.
davy.ai
Sí, existen enfoques alternativos para utilizar la palabra clave
friend
en estos escenarios.En el primer ejemplo, en lugar de utilizar
friend
para declararoperator|
, puedes declarar previamente el operador fuera de la clase y luego definirlo más adelante:De esta manera, la declaración de
operator|
puede ser vista por el compilador antes de que se le dé el valor por defecto.En el segundo ejemplo, puedes definir el operador fuera de la clase anidada y utilizar la especialización de plantillas para manejar los diferentes tipos:
De esta manera, no necesitas depender de la palabra clave
friend
para definiroperator==
como una función libre dentro de una plantilla.En general, aunque a veces es necesario utilizar
friend
para “hacer el trabajo”, generalmente existen enfoques alternativos que pueden conducir a un código más limpio y mantenible.