Sdílet prostřednictvím


/Zc:twoPhase- (zakázání dvoufázového vyhledávání názvů)

Možnost /Zc:twoPhase- v části /permissive-říká kompilátoru, aby používal původní, nevyhovující chování kompilátoru Jazyka Microsoft C++, aby parsoval a vytvořil instanci šablon tříd a šablon funkcí.

Syntaxe

/Zc:twoPhase-

Poznámky

Visual Studio 2017 verze 15.3 a novější: /permissive-V části Kompilátor používá pro překlad názvů šablon dvoufázové vyhledávání názvů. Pokud také zadáte /Zc:twoPhase-, kompilátor se vrátí k předchozí nevyhovující šabloně třídy a chování překladu názvů a nahrazení šablony funkce. Pokud /permissive- není zadáno, je výchozí chování, které nevyhovuje.

Soubory hlaviček sady Windows SDK ve verzi 10.0.15063.0 (Creators Update nebo RS2) a starší nefungují v režimu shody. /Zc:twoPhase- je nutné ke kompilaci kódu pro tyto verze sady SDK při použití /permissive-. Verze sady Windows SDK počínaje verzí 10.0.15254.0 (Fall Creators Update nebo RS3) fungují správně v režimu shody. Nevyžadují možnost /Zc:twoPhase- .

Použijte /Zc:twoPhase- , pokud váš kód vyžaduje správné kompilaci starého chování. Důrazně zvažte aktualizaci kódu tak, aby odpovídal standardu.

Chování kompilátoru v části /Zc:twoPhase-

Ve výchozím nastavení nebo v sadě Visual Studio 2017 verze 15.3 a novější, když zadáte obojí /permissive- a /Zc:twoPhase-, kompilátor používá toto chování:

  • Parsuje pouze deklaraci šablony, hlavičku třídy a seznam základních tříd. Tělo šablony je zachyceno jako stream tokenu. Nejsou analyzovány žádné tělo funkce, inicializátory, výchozí argumenty nebo argumenty noexcept. Šablona třídy je pseudoobsazena nezávazným typem k ověření správnosti deklarací v šabloně třídy. Představte si tuto šablonu třídy:

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

    Deklarace šablony, template <typename T>hlavička class Derivedtřídy a seznam public Base<T> základních tříd jsou analyzovány, ale tělo šablony je zachyceno jako datový proud tokenu.

  • Při analýze šablony funkce kompilátor analyzuje pouze podpis funkce. Tělo funkce není nikdy analyzováno. Místo toho se zachytí jako datový proud tokenu.

V důsledku toho platí, že pokud tělo šablony obsahuje chyby syntaxe, ale šablona se nikdy nenasadí, kompilátor chyby nediagnostikuje.

Dalším účinkem tohoto chování je rozlišení přetížení. K nestandardnímu chování dochází kvůli způsobu, jakým se stream tokenů rozšiřuje v lokalitě instance. Symboly, které nebyly viditelné v deklaraci šablony, můžou být viditelné v okamžiku vytvoření instance. To znamená, že se mohou účastnit řešení přetížení. Šablony se mohou měnit chování na základě kódu, který nebyl viditelný v definici šablony, na rozdíl od standardu.

Podívejte se například na tento kód:

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

Tady je výstup, když použijete výchozí režim, režim shody a režim shody s možnostmi /Zc:twoPhase- kompilátoru:

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

Při kompilaci v režimu shody v části /permissive-, tento program vytiskne "Standard two-phase", protože druhé přetížení func není viditelné, když kompilátor dosáhne šablony. Pokud přidáte /Zc:twoPhase-, program vytiskne "Microsoft one-phase". Výstup je stejný, jako když nezadáte /permissive-.

Závislé názvy jsou názvy, které závisí na parametru šablony. Tyto názvy mají chování vyhledávání, které se také liší v části /Zc:twoPhase-. V režimu shody nejsou závislé názvy vázány v bodě definice šablony. Místo toho je kompilátor vyhledá při vytvoření instance šablony. U volání funkce se závislým názvem funkce se název vyváže na funkce viditelné na webu volání v definici šablony. Přidají se další přetížení z vyhledávání závislého na argumentech, a to jak v okamžiku definice šablony, tak v okamžiku vytvoření instance šablony.

Dvoufázové vyhledávání se skládá ze dvou částí: Vyhledávání nezávislosti na názvech během definice šablony a vyhledávání závislých názvů během vytváření instancí šablony. V části /Zc:twoPhase-kompilátor neprovádí vyhledávání závislé na argumentech odděleně od nekvalifikovaného vyhledávání. To znamená, že neprovádí dvoufázové vyhledávání, takže výsledky rozlišení přetížení se můžou lišit.

Tady je další příklad:

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

Při kompilaci bez /permissive-tohoto kódu se vytiskne:

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

Při kompilaci s /permissive-, ale bez /Zc:twoPhase-, tento kód vytiskne:

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

Při kompilaci s oběma /permissive- a /Zc:twoPhase-, tento kód vytiskne:

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

V režimu shody v tfunc(1729) části /permissive-volání přeloží přetíženívoid func(long). Nepřeloží se na void func(int) přetížení, jako v části /Zc:twoPhase-. Důvodem je, že nekvalifikovaný func(int) je deklarován za definicí šablony a není nalezen prostřednictvím vyhledávání závislého na argumentu. Ale void func(S) podílí se na vyhledávání závislém na argumentech, takže se přidá do sady přetížení pro volání tfunc(s), i když je deklarován za šablonou funkce.

Aktualizace kódu pro dvoufázovou shodu

Starší verze kompilátoru nevyžadují klíčová slova template a typename všude, kde je standard C++ vyžaduje. Tato klíčová slova jsou potřebná v některých pozicích k nejednoznačnosti toho, jak by kompilátory měly analyzovat závislý název během první fáze vyhledávání. Příklad:

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

Odpovídající kompilátor parsuje Foo jako proměnnou v oboru T, což znamená, že tento kód je logický a výraz s levým operandem T::foo < a a b > (c) jako pravý operand. Pokud chcete použít Foo jako šablonu funkce, musíte označit, že se jedná o šablonu přidáním klíčového template slova:

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

Ve verzích sady Visual Studio 2017 verze 15.3 a novějších verzích /permissive-/Zc:twoPhase- kompilátor povolí tento kód bez klíčového template slova. Interpretuje kód jako volání šablony funkce s argumentem a || b, protože analyzuje pouze šablony omezeným způsobem. Výše uvedený kód se v první fázi vůbec neanalybuje. Během druhé fáze existuje dostatek kontextu, aby bylo možné zjistit, že T::Foo jde o šablonu, ne o proměnnou, takže kompilátor nevynucuje použití klíčového slova.

Toto chování lze také vidět odstraněním klíčového slova typename před názvy v těle šablony funkce, inicializátory, výchozí argumenty a argumenty noexcept. Příklad:

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

Pokud v těle funkce nepoužíváte klíčové slovo typename , tento kód se zkompiluje pod /permissive- /Zc:twoPhase-, ale ne samostatně /permissive- . Klíčové typename slovo je nutné k označení, že TYPE je závislý. Vzhledem k tomu, že tělo není analyzováno v části /Zc:twoPhase-, kompilátor nevyžaduje klíčové slovo. V /permissive- režimu shody kód bez klíčového typename slova generuje chyby. Pokud chcete migrovat kód tak, aby byl v sadě Visual Studio 2017 verze 15.3 a novější, vložte typename klíčové slovo tam, kde chybí.

Podobně zvažte tuto ukázku kódu:

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

Ve /permissive- /Zc:twoPhase- starších kompilátorech a ve starších kompilátorech vyžaduje kompilátor pouze template klíčové slovo na řádku 2. V režimu shody teď kompilátor také vyžaduje template , aby klíčové slovo na řádku 4 indikoval, že T::X<T> jde o šablonu. Vyhledejte kód, který chybí toto klíčové slovo, a zadejte ho, aby kód odpovídal standardu.

Další informace o problémech s dodržováním předpisů najdete v tématu Vylepšení shody jazyka C++ v sadě Visual Studio a nestandardním chování.

Nastavení tohoto parametru kompilátoru ve vývojovém prostředí Visual Studio

  1. Otevřete dialogové okno Stránky vlastností projektu. Podrobnosti najdete v tématu Nastavení kompilátoru C++ a vlastností sestavení v sadě Visual Studio.

  2. Vyberte stránku vlastností příkazového řádku C/C++>Vlastnosti>konfigurace.

  3. Upravte vlastnost Další možnosti tak, aby zahrnovala /Zc:twoPhase- a potom zvolte OK.

Viz také

/Zc (Shoda)