por personas para paginas nueva mundo internet hacer gente extranjeros conocer como chatear buscar amistad amigos actividades c++ scope inline friend

c++ - personas - ¿Cuál es el alcance de las funciones de amigos en línea?



hacer amigos por whatsapp (5)

Después de buscar en SO, una pregunta me enseñó que el alcance léxico de una función amigo en línea es la clase en la que está definida, lo que significa que puede acceder, por ejemplo, a los typedef de la clase sin calificarlos. Pero luego me pregunté cuál es el alcance real de tal función. GCC al menos rechaza todos mis intentos de llamarlo. ¿Alguna vez se puede invocar una función como en el ejemplo a través de medios que no sean ADL, lo cual no es posible aquí gracias a que no hay argumentos?

Las citas estándar son apreciadas, ya que actualmente no puedo acceder a mi copia.

El siguiente código

namespace foo{ struct bar{ friend void baz(){} void call_friend(); }; } int main(){ foo::baz(); // can''t access through enclosing scope of the class foo::bar::baz(); // can''t access through class scope } namespace foo{ void bar::call_friend(){ baz(); // can''t access through member function } }

resultados en estos errores:

prog.cpp: In function ‘int main()’: prog.cpp:9: error: ‘baz’ is not a member of ‘foo’ prog.cpp:10: error: ‘baz’ is not a member of ‘foo::bar’ prog.cpp: In member function ‘void foo::bar::call_friend()’: prog.cpp:15: error: ‘baz’ was not declared in this scope


"The C ++ Programming Language 3rd Edition (Stroustrap)": p279:

I. "Como una declaración de miembro, una declaración de amigo no introduce un nombre en un alcance adjunto"

II. "Una clase friend debe declararse previamente en un ámbito adjunto o definirse en el ámbito no de clase inmediatamente adjuntando la clase que lo declara como un amigo"

III. "Una función amiga se puede declarar explícitamente como clases amigas, o se puede encontrar a través de sus tipos de argumentos (§8.2.6) como si fuera declarada en el ámbito no excluyente adjuntando inmediatamente su clase".

IV. "De esto se deduce que una función amigo debe declararse explícitamente en un ámbito adjunto o tomar un argumento de su clase. De lo contrario, no se puede llamar al amigo. Por ejemplo:"

//no f() here void g(); class X{ friend void f(); //useless friend void g(); //can be found because it is declared outside of class scope friend void h(const X&); //can be found because the arguments access class members }; void f() { } //enemy of X :)

Pero en tu caso hay más que tiene que ver con el espacio de nombres, porque si pones la declaración adecuada en foo eg:

namespace foo{ struct bar{ friend void baz(const &bar){}; void call_friend(); } }

no compila Sin embargo, si lo declaras fuera de foo funciona como un amuleto. Ahora considere que, de hecho, global, local, struct y classes son, de hecho, espacios de nombres. Ahora esto lleva a la conclusión de que el baz(const &) está implícitamente definido en el alcance global.

Esto compila:

namespace foo{ struct bar{ friend void baz(const bar&){}; void call_friend(); }; } int main(){ foo::bar k; baz(k); return 0; }

Por lo tanto, hay dos problemas:

  1. La declaración de amigo no introduce un nombre en un ámbito adjunto, a menos que IV. Por lo tanto, el programa original no puede encontrar baz () porque no se ha declarado correctamente.
  2. Si IV, es decir, ADL, entonces la función se encuentra en foo, pero no se puede acceder como foo :: baz (k), debido a ADL. Tendrá que definir explícitamente baz (const bar &) en foo para acceder a él por nombre calificado.

Gracias, espero que ayude, pero sin duda, me gustó el desafío :).


¡Interesante!

Parece que el compilador no sabe a qué alcance pertenece (y para ser honesto no hay pistas) y por lo tanto no tiene alcance. Supongo que habrá una excavación estándar.

Nota: Si agrega explícitamente una declaración a un alcance particular, entonces comienza a funcionar como se esperaba.

namespace foo { void baz(); // declare it here and now it works in foo namespace etc. struct bar { friend void baz(){} void call_friend(); }; }

Buscando el estándar que encuentro:

11.3 Amigos [class.friend]

Párrafo 6

Una función se puede definir en una declaración de amigo de una clase si y solo si la clase es una clase no local (9.8), el nombre de la función no está calificado y la función tiene un ámbito de espacio de nombres .

[ Example: class M { friend void f() { } // definition of global f, a friend of M, // not the definition of a member function }; — end example ]

Párrafo 7

Dicha función está implícitamente en línea. Una función amiga definida en una clase está en el alcance (léxico) de la clase en la que está definida. Una función amiga definida fuera de la clase no es (3.4.1).

Nota:

Una función independiente que no toma un parámetro no es de mucha utilidad como amigo. Como no tendrá ningún objeto sobre el que aprovechar su amistad (supongo que objetos de duración de almacenamiento estático de alcance de archivo).


Creo que estás confundiendo friend y private . Al declarar a la función como un friend le está otorgando acceso a sus miembros privados, y no remite a otras funciones el acceso a ella. De todos modos, cualquier función miembro de una struct es accesible por cualquier objeto porque los miembros de la struct son públicos por defecto.

Sin embargo, en su caso baz no es accesible porque al hacer friend void baz(){} usted realmente no declaró la función baz , usted acaba de decir que es una función friend . Simplemente puede eliminar la palabra clave friend y resolverá todos los problemas.


Cuando declara una función friend con una identificación no calificada en una clase, nombra una función en el alcance del espacio de nombres adjunto más cercano.

Si esa función no se ha declarado previamente, la declaración de friend no hace visible esa función en ese alcance para la búsqueda normal. Hace que la función declarada sea visible para la búsqueda dependiente de argumentos.

Esto se enfatiza en muchas notas, pero la declaración definitiva se encuentra en 7.3.1.2/3 (de ISO / IEC 14882: 2011):

Cada nombre declarado por primera vez en un espacio de nombres es un miembro de ese espacio de nombres. Si una declaración de friend en una clase no local declara primero una clase o función, la clase o función amiga es un miembro del espacio de nombre más interno que lo rodea. El nombre del amigo no se encuentra mediante búsqueda no calificada (3.4.1) o por búsqueda calificada (3.4.3) hasta que se proporcione una declaración coincidente en ese ámbito de espacio de nombres (ya sea antes o después de la definición de clase que otorga amistad). Si se llama a una función amiga, su nombre se puede encontrar mediante la búsqueda de nombres que considera funciones de espacios de nombres y clases asociadas con los tipos de argumentos de función (3.4.2). Si el nombre en una declaración de friend no está calificado ni una plantilla-id y la declaración es una función o un especificador de tipo elaborado , la búsqueda para determinar si la entidad ha sido declarada previamente no considerará ningún ámbito fuera del espacio de nombre más interno .


En este ejemplo,

namespace foo{ struct bar{ friend void baz(){} void call_friend(); }; } int main(){ foo::baz(); // can''t access through enclosing scope of the class foo::bar::baz(); // can''t access through class scope } namespace foo{ void bar::call_friend(){ baz(); // can''t access through member function } }

  1. foo::baz() es inaccesible porque el nombre baz no está visible en el alcance del espacio de nombres foo . Si recuerdo correctamente (§ 3.4 / 2) se aplica aquí.

  2. foo::bar::baz() es inaccesible porque los amigos no son miembros de la clase y el alcance de la función amigo en línea es el espacio de nombres o la clase en la que existe su definición, por lo tanto, no puede acceder a ellos fuera de ese alcance.

Si coloca la declaración de baz() en foo el nombre de la función baz será visible en foo y la definición se buscará en el ámbito anidado de la bar .

namespace foo{ void baz(); // declaration at namespace scope struct bar{ friend void baz(){} }; void call_friend() { baz(); // ok } } int main() { foo::baz(); // ok, bar will be looked up in the nested scope of foo::bar. }