38 votes

Les compilateurs de CMD divergent dans le comportement d'encapsulation - lequel obtient-il le droit ?

Les compilateurs (clang-5.0.0, GCC-7.3, ICC-18 et MSVC-19) divergent w.r.t. l'accessibilité des membres de l' A ci-dessous.

class A {

    template <class> static constexpr int f() { return 0; }

    template <int> struct B {};

    template <class T> using C = B<f<T>()>;

};

En effet, considérer les points suivants usages:

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
}

Le tableau de droite indique les membres de chaque compilateur, qui nécessite d'être rendue publique à accepter le code (lorsqu'il est compilé en C++14).

À mon humble avis, la cour et le MSVC (en ignorant (C) des entrées) semblent corrects. Sauf pour la première ligne, GCC semble être complètement ignorant de l'accessibilité.

Je suis en désaccord avec clang quand il exige f publics pour instancier A::C<int> et D<int>. Comme CPI et MSVC, je pense que C et seulement C doit être public. Il est vrai que l' C utilise f mais n'est-il pas un détail d'implémentation? Notez que C utilise également B. Si clang étaient correctes, alors pourquoi n'est-il pas exiger B publics ainsi?

Enfin, permettez-nous de considérer l' (C) des entrées. MSVC exige C publics, quand il rencontre d'abord la définition de l' D, qui est, MSVC se plaint C étant privés.

Mes questions sont les suivantes:

  1. Suis-je le droit (et est donc CPI) dans mon analyse? Sinon, qui d'autre compilateur est correct, et pourquoi?
  2. Est le MSVC encore d'une autre incarnation de deux phases de l'instanciation d'un bug dans msvc?

Mise à jour: en ce qui Concerne GCC, ce qui semble être le bug signalé dans le commentaire 8, ici.

3voto

Barry Points 45207

Les questions de l' A::f<int>() et A::B<0> sont simple à répondre. f et B sont privées, et n'a aucune autre intéressant dépendances. Leur accès doit être mal formé. gcc est généralement très permissif sur le contrôle d'accès dans les modèles, il y a un metabug exceptionnel pour toutes sortes de situations (je crois que tous d'entre eux sont de la forme que gcc permet d'accéder quand il ne devrait pas, plutôt que refuse l'accès quand il le faut).

La question de l' A::C<int> est plus intéressant. C'est un alias de modèle, mais dans ce contexte ne nous fait regarder à travers les alias? Est-il dans A (dans ce cas, rendant C accessible serait suffisant) ou est-il dans le contexte dans lequel il est utilisé (dans ce cas, f, B, et C tous doivent être accessibles). Cette question est précisément GTC 1554, qui est encore en activité:

L'interaction de l'alias de modèles et de contrôle d'accès n'est pas clairement du libellé actuel de 17.6.7 [temp.alias]. Par exemple:

template <class T> using foo = typename T::foo;

class B {
  typedef int foo;
  friend struct C;
};

struct C {
  foo<B> f;    // Well-formed?
};

C'est la substitution de l' B::foo pour foo<B> fait dans le contexte de la lie d'amitié avec la classe C, ce qui rend la référence bien-formé, ou est l'accès déterminé indépendamment du contexte dans lequel l'alias de spécialisation de modèle s'affiche?

Si la réponse à cette question est que l'accès est déterminé indépendamment du contexte, des précautions doivent être prises pour s'assurer que l'accès d'un échec est encore considéré comme "dans le contexte immédiat de la fonction type" (17.9.2 [temp.déduire] le paragraphe 8), de sorte qu'il en résulte une déduction de l'échec plutôt que d'une erreur matérielle.

Bien que la question est encore ouverte, la direction semble être:

Le consensus de GTC est que l'instanciation (recherche et d'accès) pour alias modèles devraient être aussi pour d'autres modèles, dans la définition de contexte plutôt que dans le contexte où ils sont utilisés. Ils doivent encore être élargi immédiatement, cependant.

Qui est-à-dire, seulement C doit être rendu public et f et B peut rester privé. C'est la façon dont la CPI et MSVC l'interpréter. Clang a un bug qui permet alias modèles de contourner accès (15914), c'est pourquoi clang exige f à être accessible, mais pas B. Mais sinon, clang semble étendre l'alias au point d'utilisation, plutôt que le point de définition.

La question de l' D<int> suffira de suivre A::C exactement, il n'y a pas de problèmes avec GTC 1554 ici. Clang est le seul compilateur d'avoir un comportement différent entre A::C et D, à nouveau en raison d'un bug 15914.


Pour résumer, la question de l' A::C est un open core problème de langue, mais de la CPI met en œuvre la signification de la langue ici. Les autres compilateurs ont tous des problèmes avec l'accès de la vérification et de modèles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X