tipos programas programa lenguaje funciones ejemplos datos comandos codigos c++ gcc clang private encapsulation

programas - programa en c++



Los compiladores de C++ divergen en el comportamiento de encapsulación, ¿cuál lo hace bien? (1)

Las preguntas de A::f<int>() y A::B<0> son fáciles de responder. f y B son privados, y ninguno tiene otras dependencias interesantes. Acceder a ellos debe estar mal formado. Generalmente, gcc es muy permisivo sobre el control de acceso en las plantillas, hay un metabug pendiente para todo tipo de situaciones (creo que todas tienen la forma que gcc permite el acceso cuando no debería, en lugar de no permitir el acceso cuando debería).

La pregunta de A::C<int> es más interesante. Es una plantilla de alias, pero ¿en qué contexto miramos realmente el alias? Está dentro de A (en cuyo caso, hacer que C accesible sería suficiente) o está en el contexto en el que se usa (en cuyo caso, f , B y C necesitan todos ser accesibles). Esta pregunta es precisamente CWG1554 , que todavía está activa:

La interacción de las plantillas de alias y el control de acceso no está clara en la redacción actual de 17.6.7 [temp.alias]. Por ejemplo:

template <class T> using foo = typename T::foo; class B { typedef int foo; friend struct C; }; struct C { foo<B> f; // Well-formed? };

¿La sustitución de B::foo por foo<B> realiza en el contexto de la clase C amigos, haciendo que la referencia esté bien formada, o el acceso se determina independientemente del contexto en el que aparece la especialización de plantillas de alias?

Si la respuesta a esta pregunta es que el acceso se determina independientemente del contexto, se debe tener cuidado para asegurar que una falla de acceso todavía se considere como "en el contexto inmediato del tipo de función" (17.9.2 [temp.deduct] ] párrafo 8) para que resulte en una falla de deducción en lugar de un error difícil.

Aunque el problema sigue abierto, la dirección parece ser:

El consenso de CWG fue que la creación de instancias (búsqueda y acceso) para las plantillas de alias debería ser como para otras plantillas, en el contexto de definición y no en el contexto donde se usan. Sin embargo, deberían expandirse inmediatamente.

Lo que quiere decir que solo C debe hacerse público f y B pueden permanecer privados. Así es como ICC y MSVC lo interpretan. Clang tiene un error que permite que las plantillas de alias 15914 acceso ( 15914 ), por lo que clang requiere que f sea ​​accesible pero no B Pero, de lo contrario, clang parece expandir el alias en el punto de uso en lugar del punto de definición.

La pregunta de D<int> simplemente debe seguir A::C exactamente, aquí no hay problemas con CWG 1554. Clang es el único compilador que tiene un comportamiento diferente entre A::C y D , nuevamente debido al error 15914.

Para resumir, la cuestión de A::C es un problema de lenguaje de núcleo abierto, pero ICC implementa aquí el significado previsto del lenguaje. Los demás compiladores tienen problemas con las plantillas y el control de acceso.

Los compiladores ( clang-5.0.0 , GCC-7.3 , ICC-18 y MSVC-19 ) divergen de la accesibilidad wrt de los miembros de A continuación.

class A { template <class> static constexpr int f() { return 0; } template <int> struct B {}; template <class T> using C = B<f<T>()>; };

De hecho, considere los siguientes usos:

template <class T> using D = A::C<T>; int main() { // | clang | gcc | icc | msvc (void) A::f<int>(); // 1: | f | f | f | f, (C) (void) A::B<0>{}; // 2: | B | | B | B, (C) (void) A::C<int>{}; // 3: | C, f | | C | C (void) D<int>{}; // 4: | f | | C | C }

La tabla de la derecha muestra qué miembros cada compilador requiere que se hagan públicos para aceptar el código (cuando se compila para C ++ 14).

IMHO, ICC y MSVC (ignorando las entradas (C) ) parecen correctos. Excepto por la primera línea, GCC parece estar ignorando por completo el acceso.

No estoy de acuerdo con el clang cuando se requiere f para ser público para instanciar A::C<int> y D<int> . Como ICC y MSVC, creo que C y solo C tiene que ser público. Es verdad que C usa f pero ¿no es un detalle de implementación? Observe que C también usa B Si el clang fuera correcto, ¿por qué no se requiere que B sea ​​público también?

Finalmente, consideremos las entradas (C) . Msvc requiere que C sea ​​pública cuando encuentra la definición de D , es decir, MSVC se queja de que C es privado.

Mis preguntas son:

  1. ¿Tengo razón (y también lo está el ICC) en mi análisis? De lo contrario, ¿qué otro el compilador es correcto y por qué?
  2. ¿El problema de MSVC es otra encarnación del error de creación de instancias de dos fases en msvc ?

Actualización : Con respecto a GCC, este parece ser el error reportado en el comentario 8, here .