c++ c++11 templates clang++

c++ - La función de plantilla de miembro de clase A declarada como amigo en clase B no puede acceder a miembros privados de clase A(solo Clang)



c++11 templates (2)

Forzar al compilador a crear tBar::PrintDataAndAddress<tFoo> instancia de tBar::PrintDataAndAddress<tFoo> antes de usarlo resuelve el problema.

int main() { tBar bar; bar.PrintDataAndAddress(tWidget()); // Fine auto x = &tBar::PrintDataAndAddress<tFoo>; // <= make it work.... bar.PrintDataAndAddress(tFoo()); // Now fine return 0; }

Parece ser un compilador promlem ya que se parece bastante a esto:

En C ++, ¿por qué no es posible crear una función de miembro de clase de plantilla mediante el tipo de plantilla de otra clase?

Para ser un poco más precisos ... En la bar.PrintDataAndAddress(tFoo()); de bar.PrintDataAndAddress(tFoo()); el compilador debe instanciar la función miembro tBar::PrintDataAndAddress<tFoo> y al mismo tiempo debe resolver la declaración de amigo. Que son internamente dos pasos separados. Aparentemente el compilador no lo hace en el orden correcto cuando está escrito en una expresión. Para forzar al compilador a crear bar.PrintDataAndAddress(tFoo()) instancia de bar.PrintDataAndAddress(tFoo()) primero mediante el acceso al puntero de función, estos dos pasos están en el orden correcto.

Por favor, eche un vistazo a este fragmento de código. Sé que no tiene mucho sentido, solo pretende ilustrar el problema que estoy encontrando:

#include <iostream> using namespace std; struct tBar { template <typename T> void PrintDataAndAddress(const T& thing) { cout << thing.mData; PrintAddress<T>(thing); } private: // friend struct tFoo; // fixes the compilation error template <typename T> void PrintAddress(const T& thing) { cout << " - " << &thing << endl; } }; struct tFoo { friend void tBar::PrintDataAndAddress<tFoo>(const tFoo&); private: int mData = 42; }; struct tWidget { int mData = 666; }; int main() { tBar bar; bar.PrintDataAndAddress(tWidget()); // Fine bar.PrintDataAndAddress(tFoo()); // Compilation error return 0; }

El código anterior dispara el siguiente error:

source_file.cpp: 10: 3: error: ''PrintAddress'' es un miembro privado de ''tBar'' PrintAddress (cosa) ; source_file.cpp: 42: 6: note: en la creación de instancias de la plantilla de función> especialización ''tBar :: PrintDataAndAddress'' solicitada aquí bar.PrintDataAndAddress (tFoo ()); // Error de compilación source_file.cpp: 17: 7: nota: declarado privado aquí void PrintAddress (const T & thing)

pero solo en Clang ++. GCC y MSVC están de acuerdo con esto (puedes probar eso rápidamente pegando ese código en http://rextester.com/l/cpp_online_compiler_clang )

Parece como si tBar::PrintDataAndAddress<tFoo>(const tFoo&) esté usando el mismo acceso que tFoo , donde es amigo. Lo sé porque entablar amistad con tFoo en tBar corrige este problema. El problema también desaparece si tBar::PrintDataAndAddress es una función que no es de plantilla.

No he podido encontrar nada en el Estándar que explique este comportamiento. Creo que podría ser una mala interpretación de 14.6.5 - temp.inject, pero no puedo decir que lo haya leído todo.

¿Alguien sabe si Clang tiene razón al no compilar el código anterior? ¿Puede citar el texto estándar de C ++ relevante si ese es el caso?

Parece que para que ocurra este problema, el miembro privado al que se accede debe ser una función de plantilla. Por ejemplo, en el ejemplo anterior, si hacemos que PrintAddress sea una función que no sea de plantilla, el código se compilará sin errores.


Intenta agregar esto antes de la función de amigo

template <typename tFoo>