/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čkaclass Derived
třídy a seznampublic 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
Otevřete dialogové okno Stránky vlastností projektu. Podrobnosti najdete v tématu Nastavení kompilátoru C++ a vlastností sestavení v sadě Visual Studio.
Vyberte stránku vlastností příkazového řádku C/C++>Vlastnosti>konfigurace.
Upravte vlastnost Další možnosti tak, aby zahrnovala
/Zc:twoPhase-
a potom zvolte OK.