c++ - usuario - orden correcto de las instrucciones para crear una función en línea
¿Es ADL la única forma de llamar a una función en línea de un amigo? (3)
¿Es cierto, entonces, que tal función de amigo en línea solo se puede llamar con una búsqueda dependiente del argumento?
Sí. Como se especifica en [namespace.memdef]/3 :
Si una declaración de
friend
en una clase no local declara por primera vez una clase, función, plantilla de clase o plantilla de función. El amigo es un miembro del espacio de nombres que se encuentra más interno. La declaración de amigo no hace que el nombre sea visible para la búsqueda no calificada ([basic.lookup.unqual]) o la búsqueda calificada ([basic.lookup.qual]).
Dado que la única declaración de f
es su definición en línea, no se hace visible para búsquedas calificadas o no calificadas. Sin embargo, ADL tiene una disposición especial para dichas funciones de amigo, [basic.lookup.argdep]/4 :
Cuando se considera un espacio de nombres asociado, la búsqueda es la misma que la búsqueda realizada cuando el espacio de nombres asociado se usa como calificador ([namespace.qual]), excepto que:
- Cualquier función de amigo del ámbito de espacio de nombres o plantillas de función de amigo declaradas en clases asociadas son visibles dentro de sus respectivos espacios de nombre, incluso si no son visibles durante una búsqueda ordinaria ([class.friend]).
En cuanto a tu pregunta de bonificación, un lambda debería hacerlo:
auto exposed_g = [](S const& s){ g(s); };
Envuelve el ADL en su cuerpo. Aunque se aplican las advertencias habituales sobre la deducción del tipo de devolución. Será un valor (suponiendo que no devuelvas el void
).
Definamos f
, como función amiga de S
, dentro de la declaración de S
:
struct S
{
friend void f() {}
};
No puedo encontrar la manera de llamar a f
.
¿Es cierto, entonces, que tal función de amigo en línea solo se puede llamar con una búsqueda dependiente del argumento ?
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
// f(); // error: ''f'' was not declared in this scope
// S::f(); // error: ''f'' is not a member of ''S''
g(s);
// S::g(s); // error: ''g'' is not a member of ''S''
}
Bonificación: ¿qué sucede si deseo obtener una función-puntero / std::function
/ lambda to g
?
El nombre f
se declara en una declaración de amigo , incluso se convierte en el miembro del namespace de namespace que contiene S
, pero no es visible para la búsqueda de nombres, a menos que se vuelva a declarar en el ámbito del espacio de nombres. Si no, solo se puede encontrar por ADL .
Los nombres introducidos por declaraciones de amigos dentro de una clase
X
no local se convierten en miembros del espacio de nombres deX
más íntimo, pero no se hacen visibles en la búsqueda de nombres ordinarios (ni calificados ni calificados) a menos que se proporcione una declaración coincidente en el ámbito del espacio de nombres, antes o después de la definición de la clase. Dicho nombre se puede encontrar a través de ADL que considera tanto los espacios de nombres como las clases.
No. Deberías declarar la función correctamente.
struct S;
inline void f();
inline void g(S const&);
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
f(); // Ok
// S::f(); // error: ''f'' is not a member of ''S''
g(s);
// S::g(s); // error: ''g'' is not a member of ''S''
}