¿Por qué la verificación de control de acceso habitual se aplica a los nombres utilizados para especificar una instanciación explícita cuando se accede a través de parámetros de plantilla?

El estándar C ++ establece lo siguiente en la nota 14.7.2 / 12 [temp.explicit]:

Las reglas habituales de verificación de acceso no se aplican a los nombres utilizados para especificar instancias explícitas. [Nota: en particular, los argumentos de la plantilla y los nombres utilizados en el declarador de funciones (incluidos los tipos de parámetros, los tipos de devolución y las especi fi caciones de excepción) pueden ser tipos u objetos privados que normalmente no serían accesibles y la plantilla puede ser una plantilla miembro o una función miembro. Lo que normalmente no sería accesible. – nota final]

Espero que se me permita usar una plantilla si puedo crear una instancia.

Intenté con gcc-4.8.2 y obtengo el comportamiento esperado cuando accedo a miembros privados de clases con nombres explícitos. Sin embargo, las reglas de verificación de acceso se aplican cuando accedo a miembros privados a través de parámetros de plantilla. ¿Es esto un error en gcc, o me estoy perdiendo algo?

En el código a continuación, la única diferencia entre “tener éxito” y “fallar” es que el primero accede al miembro privado directamente a través de “A”, mientras que el último accede a él a través del parámetro de plantilla “T”. El comstackdor se queja de que privateFoobar es privado en ese contexto.

#include  #include  struct A { private: std::string privateFoobar() {return "private foobar!";} }; typedef std::string (A::*Foobar)(); template  struct Access { static Type getValue() {return value;} }; template  struct IndirectAccess { static Foobar succeeds() {return Access::getValue();} static Foobar fails() {return Access::getValue();} }; template class Access; int main() { std::cout << (A().*Access::getValue())() << std::endl; std::cout << (A().*IndirectAccess::succeeds())() << std::endl; std::cout << (A().*IndirectAccess::fails())() << std::endl; } 

En caso de que se esté preguntando cuál es el caso de uso para una ofensa de este tipo: crear un marco que automatice la configuración de una aplicación en función de las opciones de implementación para los componentes seleccionados.

Las instancias explícitas deben estar en el ámbito del espacio de nombres, lo que significa que los miembros privados de las clases normalmente no serían accesibles. Sin la regla que usted cita, esto sería imposible:

 class Foo { private: struct Bar; template class Baz { }; public: void f(); // does things with Baz }; // explicit instantiation declaration extern template class Foo::Baz; 

Sin esa regla, no podría nombrar Foo::Bar o incluso Foo::Baz en el ámbito del espacio de nombres, porque esos nombres son privados para Foo .

Ya que no estoy usando Foo::Bar o Foo::Baz aquí, simplemente refiriéndome a sus nombres para decirle al comstackdor que estoy creando una instancia de la plantilla en otro lugar, no hay una violación de acceso real (aunque es posible usar esta Regla para realizar un truco muy astuto no posible de lo contrario).

De manera similar, cuando escribo la definición de creación de instancias explícita en otro archivo, necesito poder referirme a los nombres privados nuevamente en el ámbito del espacio de nombres.