Tengo el siguiente código que se está compilando bien con VS2015, pero no con gcc (cualquier versión). Para mí, el espacio de nombres de class A_Creator está correctamente definido (es decir, el espacio de nombres raíz) porque se ha declarado adelante en la parte superior del programa. ¿Por qué gcc no puede detectar el espacio de nombres de la clase A_Creator correctamente? ¿Qué compilador es el correcto?

#include <list>

class A_Creator;

namespace X
{
class A
{
private:
   int mX;

   A(int x) :
      mX(x)
   {}

   // GCC complains about this line, and it should be changed to ::A_Creator
   // On VS2015, both of them are working
   friend class A_Creator; 
};

} // namespace X

class A_Creator
{
public:

   std::list<X::A> TestOnList(int z)
   {
      std::list<X::A> a_list;
      a_list.push_back(X::A(z));

      return a_list;
   }
};


int main()
{
   A_Creator a_cr;
   auto x = a_cr.TestOnList(12);
}
3
Gupta 13 dic. 2019 a las 20:23

2 respuestas

La mejor respuesta

De C ++ 11 [namespace.memdef] / 3 :

Si el nombre en una declaración friend no está calificado ni es un id-plantilla y la declaración es una función o un elaborated-type-specifier , la búsqueda para determinar si la entidad ha sido declarada previamente no considerará ámbitos fuera del espacio de nombres cerrado más interno. [Nota: Las otras formas de declaraciones de amigos no pueden declarar un nuevo miembro del espacio de nombres más cercano y, por lo tanto, seguir las reglas de búsqueda habituales. - nota final]

Dado que ha elaborado un especificador de tipo en la declaración friend (friend class A_Creator;), las declaraciones anteriores solo se buscarán en el espacio de nombres más cercano ::X. Entonces, gcc tiene razón.
Un extracto relevante del Ejemplo en [namespace.memdef] / 3, con declaración de reenvío global de una función en lugar de una clase:

void h(int);
namespace A {
  class X {
    class Y {
      friend void h(int);       // A::h is a friend
                                // ::h not considered
    };
  };
}
5
Language Lawyer 13 dic. 2019 a las 19:44

Quizás es porque tu constructor es privado. Intente hacer público su constructor y vea qué sucede.

Funciona para mí cuando A (int x) es público, pero no cuando es privado.

Eclipse CDT, Centos 7

-5
snakedoctor 13 dic. 2019 a las 17:54