Share via


/Zc:twoPhase- (disabilitare la ricerca del nome in due fasi)

L'opzione /Zc:twoPhase- , in /permissive-, indica al compilatore di usare il comportamento del compilatore Microsoft C++ originale e non conforme per analizzare e creare istanze di modelli di classe e modelli di funzione.

Sintassi

/Zc:twoPhase-

Osservazioni:

Visual Studio 2017 versione 15.3 e successive: in /permissive-, il compilatore usa la ricerca dei nomi in due fasi per la risoluzione dei nomi del modello. Se si specifica /Zc:twoPhase-anche , il compilatore ripristina il modello di classe precedente non conforme e il comportamento di sostituzione e risoluzione dei nomi del modello di funzione. Quando /permissive- non viene specificato, il comportamento non conforme è l'impostazione predefinita.

I file di intestazione di Windows SDK nella versione 10.0.15063.0 (Creators Update o RS2) e precedenti non funzionano in modalità di conformità. /Zc:twoPhase- è necessario per compilare il codice per tali versioni dell'SDK quando si usa /permissive-. Le versioni di Windows SDK a partire dalla versione 10.0.15254.0 (Fall Creators Update o RS3) funzionano correttamente in modalità di conformità. Non richiedono l'opzione /Zc:twoPhase- .

Usare /Zc:twoPhase- se il codice richiede il comportamento precedente per la compilazione corretta. È consigliabile aggiornare il codice in modo che sia conforme allo standard.

Comportamento del compilatore in /Zc:twoPhase-

Per impostazione predefinita, o in Visual Studio 2017 versione 15.3 e successive quando si specificano entrambi /permissive- e /Zc:twoPhase-, il compilatore usa questo comportamento:

  • Analizza solo la dichiarazione del modello, l'intestazione della classe e l'elenco delle classi di base. Il corpo del modello viene acquisito come flusso di token. Non vengono analizzati corpi di funzione, inizializzatori, argomenti predefiniti o argomenti noexcept. Il modello di classe è pseudo-creato su un tipo provvisorio per verificare che le dichiarazioni nel modello di classe siano corrette. Si consideri questo modello di classe:

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

    La dichiarazione del modello, template <typename T>, l'intestazione class Deriveddella classe e l'elenco public Base<T> di classi base vengono analizzate, ma il corpo del modello viene acquisito come flusso di token.

  • Quando analizza un modello di funzione, il compilatore analizza solo la firma della funzione. Il corpo della funzione non viene mai analizzato. Viene invece acquisito come flusso di token.

Di conseguenza, se il corpo del modello presenta errori di sintassi, ma il modello non viene mai creata un'istanza, il compilatore non diagnostica gli errori.

Un altro effetto di questo comportamento è la risoluzione dell'overload. Il comportamento non standard si verifica a causa del modo in cui il flusso del token viene espanso nel sito di creazione di istanze. I simboli non visibili nella dichiarazione del modello possono essere visibili al momento della creazione di istanze. Ciò significa che possono partecipare alla risoluzione dell'overload. È possibile che i modelli modifichino il comportamento in base al codice non visibile nella definizione del modello, contrariamente allo standard.

Si consideri ad esempio questo codice:

// 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);
}

Ecco l'output quando si usa la modalità predefinita, la modalità di conformità e la modalità di conformità con /Zc:twoPhase- le opzioni del compilatore:

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

Quando viene compilata in modalità di conformità in /permissive-, questo programma stampa "Standard two-phase", perché il secondo overload di func non è visibile quando il compilatore raggiunge il modello. Se si aggiunge /Zc:twoPhase-, il programma stampa "Microsoft one-phase". L'output è uguale a quando non si specifica /permissive-.

I nomi dipendenti sono nomi che dipendono da un parametro di modello. Questi nomi hanno un comportamento di ricerca diverso anche in /Zc:twoPhase-. In modalità di conformità, i nomi dipendenti non sono associati al punto della definizione del modello. Al contrario, il compilatore li cerca quando crea un'istanza del modello. Per le chiamate di funzione con un nome di funzione dipendente, il nome viene associato alle funzioni visibili nel sito di chiamata nella definizione del modello. Vengono aggiunti altri overload dalla ricerca dipendente dall'argomento, sia al punto della definizione del modello che al momento della creazione di istanze del modello.

La ricerca in due fasi è costituita da due parti: la ricerca di nomi non dipendenti durante la definizione del modello e la ricerca di nomi dipendenti durante la creazione di istanze del modello. In /Zc:twoPhase-il compilatore non esegue la ricerca dipendente dall'argomento separatamente dalla ricerca non qualificata. Ovvero, non esegue una ricerca in due fasi, quindi i risultati della risoluzione dell'overload possono essere diversi.

Di seguito è riportato un altro esempio:

// 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);
}

Quando viene compilato senza /permissive-, questo codice stampa:

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

Quando viene compilato con /permissive-, ma senza /Zc:twoPhase-, questo codice stampa:

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

Quando viene compilato con e /permissive-/Zc:twoPhase-, questo codice stampa:

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

In modalità di conformità in /permissive-, la chiamata tfunc(1729) viene risolta nell'overload void func(long) . Non si risolve nell'overload void func(int) , come in /Zc:twoPhase-. Il motivo è che l'oggetto non qualificato func(int) viene dichiarato dopo la definizione del modello e non viene trovato tramite la ricerca dipendente dall'argomento. Ma void func(S) fa parte della ricerca dipendente dall'argomento, quindi viene aggiunto al set di overload per la chiamata tfunc(s), anche se viene dichiarato dopo il modello di funzione.

Aggiornare il codice per la conformità in due fasi

Le versioni precedenti del compilatore non richiedono le parole chiave template e typename ovunque lo standard C++ li richieda. Queste parole chiave sono necessarie in alcune posizioni per disambiguare il modo in cui i compilatori devono analizzare un nome dipendente durante la prima fase di ricerca. Ad esempio:

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

Un compilatore conforme analizza Foo come variabile nell'ambito di T, ovvero questo codice è un'espressione logica o con T::foo < a come operando sinistro e b > (c) come operando destro. Se si intende usare Foo come modello di funzione, è necessario indicare che si tratta di un modello aggiungendo la template parola chiave :

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

Nelle versioni di Visual Studio 2017 versione 15.3 e successive, quando /permissive- e /Zc:twoPhase- vengono specificati, il compilatore consente questo codice senza la template parola chiave . Interpreta il codice come una chiamata a un modello di funzione con un argomento di a || b, perché analizza solo i modelli in modo limitato. Il codice precedente non viene analizzato affatto nella prima fase. Durante la seconda fase, esiste un contesto sufficiente per indicare che T::Foo si tratta di un modello anziché di una variabile, quindi il compilatore non impone l'uso della parola chiave.

Questo comportamento può essere visualizzato anche eliminando la parola chiave typename prima dei nomi nei corpi dei modelli di funzione, inizializzatori, argomenti predefiniti e argomenti noexcept. Ad esempio:

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

Se non si usa la parola chiave typename nel corpo della funzione, questo codice viene compilato in /permissive- /Zc:twoPhase-, ma non /permissive- da solo. La typename parola chiave è necessaria per indicare che l'oggetto TYPE è dipendente. Poiché il corpo non viene analizzato in /Zc:twoPhase-, il compilatore non richiede la parola chiave . In /permissive- modalità di conformità, il codice senza la typename parola chiave genera errori. Per eseguire la migrazione del codice alla conformità in Visual Studio 2017 versione 15.3 e successive, inserire la typename parola chiave in cui manca.

Analogamente, si consideri questo esempio di codice:

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

In /permissive- /Zc:twoPhase- e nei compilatori meno recenti, il compilatore richiede solo la parola chiave nella template riga 2. In modalità di conformità, il compilatore richiede ora anche la template parola chiave nella riga 4 per indicare che T::X<T> si tratta di un modello. Cercare il codice mancante di questa parola chiave e specificarlo per rendere il codice conforme allo standard.

Per altre informazioni sui problemi di conformità, vedere Miglioramenti della conformità C++ in Visual Studio e comportamento non standard.

Per impostare l'opzione del compilatore nell'ambiente di sviluppo di Visual Studio

  1. Aprire la finestra di dialogo Pagine delle proprietà del progetto. Per informazioni dettagliate, vedere Impostare il compilatore e le proprietà di compilazione.

  2. Selezionare la pagina delle proprietà Proprietà di configurazione>C/C++>Riga di comando.

  3. Modificare la proprietà Opzioni aggiuntive per includere /Zc:twoPhase- e quindi scegliere OK.

Vedi anche

/Zc (Conformità)