Partager via


/Zc:twoPhase- (désactiver la recherche de noms en deux phases)

L’option /Zc:twoPhase- , sous /permissive-, indique au compilateur d’utiliser le comportement du compilateur Microsoft C++ d’origine et non conforme pour analyser et instancier des modèles de classe et des modèles de fonction.

Syntaxe

/Zc:twoPhase-

Notes

Visual Studio 2017 version 15.3 et ultérieure : Sous /permissive-, le compilateur utilise la recherche de noms en deux phases pour la résolution de noms de modèle. Si vous spécifiez /Zc:twoPhase-également, le compilateur revient à son modèle de classe et à son comportement de substitution de modèle de fonction et de modèle de fonction précédents. Lorsqu’il /permissive- n’est pas spécifié, le comportement non conforme est la valeur par défaut.

Les fichiers d’en-tête du SDK Windows dans la version 10.0.15063.0 (Creators Update ou RS2) et les versions antérieures ne fonctionnent pas en mode de conformité. /Zc:twoPhase- est nécessaire pour compiler du code pour ces versions du Kit de développement logiciel (SDK) lorsque vous utilisez /permissive-. Les versions du Kit de développement logiciel (SDK) Windows commençant par la version 10.0.15254.0 (Fall Creators Update ou RS3) fonctionnent correctement en mode de conformité. Ils ne nécessitent pas l’option /Zc:twoPhase- .

Utilisez /Zc:twoPhase- si votre code nécessite l’ancien comportement à compiler correctement. Envisagez fortement de mettre à jour votre code pour qu’il soit conforme à la norme.

Comportement du compilateur sous /Zc:twoPhase-

Par défaut, ou dans Visual Studio 2017 version 15.3 et ultérieure lorsque vous spécifiez les deux /permissive- et /Zc:twoPhase-que le compilateur utilise ce comportement :

  • Il analyse uniquement la déclaration de modèle, la tête de classe et la liste des classes de base. Le corps du modèle est capturé sous forme de flux de jetons. Aucun corps de fonction, initialiseurs, arguments par défaut ou arguments noexcept n’est analysé. Le modèle de classe est pseudo-instancié sur un type provisoire pour vérifier que les déclarations dans le modèle de classe sont correctes. Considérez ce modèle de classe :

    template <typename T> class Derived : public Base<T> { ... }
    

    La déclaration de modèle, la template <typename T>tête class Derivedde classe et la liste public Base<T> de classes de base sont analysées, mais le corps du modèle est capturé sous forme de flux de jetons.

  • Lorsqu’il analyse un modèle de fonction, le compilateur analyse uniquement la signature de fonction. Le corps de la fonction n’est jamais analysé. Au lieu de cela, elle est capturée en tant que flux de jetons.

Par conséquent, si le corps du modèle a des erreurs de syntaxe, mais que le modèle n’est jamais instancié, le compilateur ne diagnostique pas les erreurs.

Un autre effet de ce comportement est dans la résolution de surcharge. Le comportement non standard se produit en raison de la façon dont le flux de jetons est développé sur le site d’instanciation. Les symboles qui n’étaient pas visibles à la déclaration de modèle peuvent être visibles au point d’instanciation. Cela signifie qu’ils peuvent participer à la résolution de surcharge. Vous pouvez trouver des modèles modifier le comportement en fonction du code qui n’était pas visible lors de la définition du modèle, contrairement à la norme.

Considérez par exemple le code suivant :

// zctwophase.cpp
// To test options, compile by using
// cl /EHsc /nologo /W4 zctwophase.cpp
// cl /EHsc /nologo /W4 /permissive- zctwophase.cpp
// cl /EHsc /nologo /W4 /permissive- /Zc:twoPhase- zctwophase.cpp

#include <cstdio>

void func(long) { std::puts("Standard two-phase") ;}

template<typename T> void g(T x)
{
    func(0);
}

void func(int) { std::puts("Microsoft one-phase"); }

int main()
{
    g(6174);
}

Voici la sortie lorsque vous utilisez le mode par défaut, le mode de conformité et le mode de conformité avec /Zc:twoPhase- les options du compilateur :

C:\Temp>cl /EHsc /nologo /W4 zctwophase.cpp && zctwophase
zctwophase.cpp
Microsoft one-phase

C:\Temp>cl /EHsc /nologo /W4 /permissive- zctwophase.cpp && zctwophase
zctwophase.cpp
Standard two-phase

C:\Temp>cl /EHsc /nologo /W4 /permissive- /Zc:twoPhase- zctwophase.cpp && zctwophase
zctwophase.cpp
Microsoft one-phase

Lorsqu’il est compilé en mode /permissive-de conformité, ce programme imprime « »,Standard two-phase car la deuxième surcharge func n’est pas visible lorsque le compilateur atteint le modèle. Si vous ajoutez /Zc:twoPhase-, le programme imprime «Microsoft one-phase ». La sortie est la même que lorsque vous ne spécifiez /permissive-pas .

Les noms dépendants sont des noms qui dépendent d’un paramètre de modèle. Ces noms ont un comportement de recherche qui est également différent sous /Zc:twoPhase-. En mode de conformité, les noms dépendants ne sont pas liés au point de la définition du modèle. Au lieu de cela, le compilateur les recherche quand il instancie le modèle. Pour les appels de fonction avec un nom de fonction dépendant, le nom est lié aux fonctions visibles sur le site d’appel dans la définition du modèle. D’autres surcharges de recherche dépendantes de l’argument sont ajoutées, à la fois au point de la définition du modèle et au point d’instanciation du modèle.

La recherche en deux phases se compose de deux parties : la recherche de noms non dépendants pendant la définition de modèle et la recherche de noms dépendants pendant l’instanciation du modèle. Sous /Zc:twoPhase-, le compilateur ne fait pas de recherche dépendante des arguments séparément de la recherche non qualifiée. Autrement dit, il n’effectue pas de recherche en deux phases, de sorte que les résultats de la résolution de surcharge peuvent être différents.

Voici un autre exemple :

// zctwophase1.cpp
// To test options, compile by using
// cl /EHsc /W4 zctwophase1.cpp
// cl /EHsc /W4 /permissive- zctwophase1.cpp
// cl /EHsc /W4 /permissive- /Zc:twoPhase- zctwophase1.cpp

#include <cstdio>

void func(long) { std::puts("func(long)"); }

template <typename T> void tfunc(T t) {
    func(t);
}

void func(int) { std::puts("func(int)"); }

namespace NS {
    struct S {};
    void func(S) { std::puts("NS::func(NS::S)"); }
}

int main() {
    tfunc(1729);
    NS::S s;
    tfunc(s);
}

Lorsqu’il est compilé sans /permissive-, ce code imprime :

func(int)
NS::func(NS::S)

Lorsqu’il est compilé avec /permissive-, mais sans /Zc:twoPhase-, ce code imprime :

func(long)
NS::func(NS::S)

En cas de compilation avec les deux /permissive- et /Zc:twoPhase-, ce code imprime :

func(int)
NS::func(NS::S)

En mode de conformité sous /permissive-, l’appel tfunc(1729) se résout en void func(long) surcharge. Elle ne se résout pas à la void func(int) surcharge, comme sous /Zc:twoPhase-. La raison est que le non qualifié func(int) est déclaré après la définition du modèle et qu’il n’est pas trouvé par le biais d’une recherche dépendante de l’argument. Mais void func(S) participe à la recherche dépendante de l’argument, elle est donc ajoutée au jeu de surcharges de l’appel tfunc(s), même si elle est déclarée après le modèle de fonction.

Mettre à jour votre code pour la conformité en deux phases

Les versions antérieures du compilateur ne nécessitent pas les mots clés template et typename partout où la norme C++ les requiert. Ces mots clés sont nécessaires dans certaines positions pour désambiguer la façon dont les compilateurs doivent analyser un nom dépendant pendant la première phase de recherche. Par exemple :

T::Foo<a || b>(c);

Un compilateur conforme analyse Foo en tant que variable dans l’étendue de T, ce qui signifie que ce code est une expression logique avec T::foo < a comme opérande gauche et b > (c) comme opérande droit. Si vous voulez utiliser Foo comme modèle de fonction, vous devez indiquer qu’il s’agit d’un modèle en ajoutant le template mot clé :

T::template Foo<a || b>(c);

Dans les versions de Visual Studio 2017 version 15.3 et ultérieures, quand /permissive- et /Zc:twoPhase- sont spécifiées, le compilateur autorise ce code sans le template mot clé. Il interprète le code comme un appel à un modèle de fonction avec un argument de a || b, car il analyse uniquement les modèles d’une manière limitée. Le code ci-dessus n’est pas analysé du tout dans la première phase. Pendant la deuxième phase, il y a suffisamment de contexte pour indiquer qu’il T::Foo s’agit d’un modèle plutôt qu’une variable, de sorte que le compilateur n’applique pas l’utilisation du mot clé.

Ce comportement peut également être vu en éliminant le mot clé typename avant les noms dans les corps de modèle de fonction, les initialiseurs, les arguments par défaut et les arguments noexcept. Par exemple :

template<typename T>
typename T::TYPE func(typename T::TYPE*)
{
    /* typename */ T::TYPE i;
}

Si vous n’utilisez pas le mot clé typename dans le corps de la fonction, ce code se compile sous /permissive- /Zc:twoPhase-, mais pas seul /permissive- . Le typename mot clé est requis pour indiquer que celui-ci TYPE dépend. Étant donné que le corps n’est pas analysé sous /Zc:twoPhase-, le compilateur ne nécessite pas le mot clé. En /permissive- mode de conformité, le code sans le typename mot clé génère des erreurs. Pour migrer votre code vers la conformité dans Visual Studio 2017 version 15.3 et au-delà, insérez le typename mot clé dans lequel il est manquant.

De même, considérez cet exemple de code :

template<typename T>
typename T::template X<T>::TYPE func(typename T::TYPE)
{
    typename T::/* template */ X<T>::TYPE i;
}

Sous /permissive- /Zc:twoPhase- et dans les compilateurs plus anciens, le compilateur requiert uniquement le mot clé sur la template ligne 2. En mode de conformité, le compilateur requiert désormais également le mot clé sur la template ligne 4 pour indiquer qu’il T::X<T> s’agit d’un modèle. Recherchez le code qui manque ce mot clé et fournissez-le pour rendre votre code conforme à la norme.

Pour plus d’informations sur les problèmes de conformité, consultez les améliorations de conformité C++ dans le comportement de Visual Studio et non standard.

Pour définir cette option du compilateur dans l'environnement de développement Visual Studio

  1. Ouvrez la boîte de dialogue Pages de propriété du projet. Pour plus d’informations, consultez Définir le compilateur C++ et les propriétés de build dans Visual Studio.

  2. Sélectionnez la page de propriétés Propriétés de configuration>C/C++>Ligne de commande.

  3. Modifiez la propriété Options supplémentaires à inclure /Zc:twoPhase- , puis choisissez OK.

Voir aussi

/Zc (Conformité)