Udostępnij za pośrednictwem


/Zc:twoPhase- (wyłącz wyszukiwanie nazw dwufazowych)

Opcja /Zc:twoPhase- w obszarze /permissive-informuje kompilator o użyciu oryginalnego, niezgodnego zachowania kompilatora Microsoft C++ do analizowania i tworzenia wystąpień szablonów klas i szablonów funkcji.

Składnia

/Zc:twoPhase-

Uwagi

Program Visual Studio 2017 w wersji 15.3 lub nowszej: w obszarze /permissive-kompilator używa wyszukiwania nazw dwufazowych na potrzeby rozpoznawania nazw szablonów. Jeśli określisz /Zc:twoPhase-również parametr , kompilator powróci do poprzedniego niezgodnego szablonu klasy i rozpoznawania nazw szablonów funkcji i zachowania podstawienia. Jeśli /permissive- nie zostanie określony, zachowanie niezgodne jest domyślne.

Pliki nagłówkowe zestawu Windows SDK w wersji 10.0.15063.0 (aktualizacja dla twórców lub RS2) i starsze wersje nie działają w trybie zgodności. /Zc:twoPhase- program jest wymagany do skompilowania kodu dla tych wersji zestawu SDK w przypadku korzystania z programu /permissive-. Wersje zestawu Windows SDK począwszy od wersji 10.0.15254.0 (Fall Creators Update lub RS3) działają poprawnie w trybie zgodności. Nie wymagają /Zc:twoPhase- tej opcji.

Użyj /Zc:twoPhase- polecenia , jeśli kod wymaga prawidłowego skompilowania starego zachowania. Zdecydowanie rozważ zaktualizowanie kodu w celu zachowania zgodności ze standardem.

Zachowanie kompilatora w obszarze /Zc:twoPhase-

Domyślnie lub w programie Visual Studio 2017 w wersji 15.3 lub nowszej podczas określania parametrów /permissive- i /Zc:twoPhase-kompilator używa tego zachowania:

  • Analizuje tylko deklarację szablonu, głowę klasy i listę klas bazowych. Treść szablonu jest przechwytywana jako strumień tokenu. Nie są analizowane żadne jednostki funkcji, inicjatory, argumenty domyślne lub argumenty noexcept. Szablon klasy jest pseudo wystąpienia w typie wstępnym, aby sprawdzić, czy deklaracje w szablonie klasy są poprawne. Rozważmy ten szablon klasy:

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

    Deklaracja szablonu , template <typename T>nagłówek class Derivedklasy i lista public Base<T> klas bazowych są analizowane, ale treść szablonu jest przechwytywana jako strumień tokenu.

  • Podczas analizowania szablonu funkcji kompilator analizuje tylko podpis funkcji. Treść funkcji nigdy nie jest analizowana. Zamiast tego jest przechwytywany jako strumień tokenu.

W związku z tym, jeśli treść szablonu zawiera błędy składni, ale szablon nigdy nie zostanie utworzone, kompilator nie diagnozuje błędów.

Innym efektem tego zachowania jest rozwiązanie przeciążenia. Nietypowe zachowanie występuje ze względu na sposób, w jaki strumień tokenu jest rozszerzany w lokacji wystąpienia. Symbole, które nie były widoczne w deklaracji szablonu, mogą być widoczne w momencie tworzenia wystąpienia. Oznacza to, że mogą uczestniczyć w rozwiązywaniu przeciążenia. Szablony mogą zmieniać zachowanie na podstawie kodu, który nie był widoczny w definicji szablonu, w przeciwieństwie do standardu.

Na przykład, rozważmy ten kod:

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

Oto dane wyjściowe, gdy używasz trybu domyślnego, trybu zgodności i trybu zgodności z opcjami /Zc:twoPhase- kompilatora:

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

Po skompilowaniu w trybie zgodności w obszarze /permissive-program wyświetla tekst "Standard two-phase", ponieważ drugie przeciążenie func elementu nie jest widoczne, gdy kompilator osiągnie szablon. W przypadku dodania /Zc:twoPhase-program wyświetli ciąg "Microsoft one-phase". Dane wyjściowe są takie same jak w przypadku, gdy nie określisz /permissive-elementu .

Nazwy zależne to nazwy , które zależą od parametru szablonu. Te nazwy mają zachowanie odnośnika, które również różni się w obszarze /Zc:twoPhase-. W trybie zgodności nazwy zależne nie są powiązane w punkcie definicji szablonu. Zamiast tego kompilator wyszukuje je podczas tworzenia wystąpienia szablonu. W przypadku wywołań funkcji z zależną nazwą funkcji nazwa jest powiązana z funkcjami widocznymi w lokacji wywołania w definicji szablonu. Dodawane są inne przeciążenia z wyszukiwania zależnego od argumentów, zarówno w punkcie definicji szablonu, jak i w momencie tworzenia wystąpienia szablonu.

Wyszukiwanie dwufazowe składa się z dwóch części: wyszukiwanie nazw niezależnych podczas definicji szablonu oraz wyszukiwanie nazw zależnych podczas tworzenia wystąpienia szablonu. W obszarze /Zc:twoPhase-kompilator nie wykonuje wyszukiwania zależnego od argumentów niezależnie od niekwalifikowanego wyszukiwania. Oznacza to, że nie wykonuje wyszukiwania dwufazowego, więc wyniki rozpoznawania przeciążeń mogą być różne.

Oto kolejny przykład:

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

Po skompilowaniu bez /permissive-polecenia ten kod drukuje:

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

Po skompilowaniu za pomocą /permissive-polecenia , ale bez /Zc:twoPhase-tego kodu jest wyświetlany następujący kod:

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

Po skompilowaniu za pomocą poleceń /permissive- i /Zc:twoPhase-ten kod jest wyświetlany:

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

W trybie zgodności w obszarze /permissive-wywołanie tfunc(1729) jest rozpoznawane jako void func(long) przeciążenie. Nie jest rozpoznawany jako void func(int) przeciążenie, jak w obszarze /Zc:twoPhase-. Przyczyną jest zadeklarowanie func(int) niekwalifikowanego po definicji szablonu i nie można go znaleźć za pośrednictwem wyszukiwania zależnego od argumentów. Jednak void func(S) nie uczestniczy w wyszukiwaniu zależnym od argumentów, dlatego jest dodawany do zestawu przeciążenia dla wywołania tfunc(s), mimo że jest zadeklarowany po szablonie funkcji.

Aktualizowanie kodu pod kątem zgodności dwufazowej

Starsze wersje kompilatora nie wymagają słów kluczowych template i typename wszędzie, gdzie język C++ Standard ich wymaga. Te słowa kluczowe są potrzebne w niektórych pozycjach, aby uściślić, jak kompilatory powinny analizować nazwę zależną w pierwszej fazie wyszukiwania. Na przykład:

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

Zgodny kompilator analizuje Foo jako zmienną w zakresie T, co oznacza, że ten kod jest wyrażeniem logicznym lub T::foo < a wyrażeniem jako lewy operand i b > (c) jako prawy operand. Jeśli chcesz użyć Foo jako szablonu funkcji, musisz wskazać, że jest to szablon, dodając template słowo kluczowe:

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

W wersjach programu Visual Studio 2017 w wersji 15.3 lub nowszej /permissive- /Zc:twoPhase- kompilator zezwala na ten kod bez słowa kluczowego template . Interpretuje kod jako wywołanie szablonu funkcji z argumentem a || b, ponieważ analizuje tylko szablony w ograniczony sposób. Powyższy kod nie jest analizowany w ogóle w pierwszej fazie. W drugiej fazie istnieje wystarczająca ilość kontekstu, aby stwierdzić, że T::Foo jest to szablon, a nie zmienna, więc kompilator nie wymusza użycia słowa kluczowego.

To zachowanie można również zobaczyć, eliminując słowo kluczowe typename przed nazwami w treści szablonu funkcji, inicjatorami, argumentami domyślnymi i argumentami noexcept. Na przykład:

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

Jeśli nie używasz słowa kluczowego typename w treści funkcji, ten kod kompiluje się w obszarze /permissive- /Zc:twoPhase-, ale nie tylko w obszarze /permissive- . Słowo typename kluczowe jest wymagane, aby wskazać, że element jest zależny TYPE . Ponieważ treść nie jest analizowana w obszarze /Zc:twoPhase-, kompilator nie wymaga słowa kluczowego. W /permissive- trybie zgodności kod bez słowa kluczowego typename generuje błędy. Aby przeprowadzić migrację kodu w celu zachowania zgodności w programie Visual Studio 2017 w wersji 15.3 lub nowszej, wstaw typename słowo kluczowe, w którym go brakuje.

Podobnie rozważmy ten przykładowy kod:

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

W starszych /permissive- /Zc:twoPhase- kompilatorach kompilator wymaga tylko słowa kluczowego template w wierszu 2. W trybie zgodności kompilator wymaga teraz również słowa kluczowego template w wierszu 4, aby wskazać, że T::X<T> jest to szablon. Poszukaj kodu, który nie ma tego słowa kluczowego, i podaj go, aby kod był zgodny ze standardem.

Aby uzyskać więcej informacji na temat problemów ze zgodnością, zobacz Ulepszenia zgodności języka C++ w programie Visual Studio i zachowanie niezgodne.

Aby ustawić tę opcję kompilatora w środowisku programowania Visual Studio

  1. Otwórz okno dialogowe Strony właściwości projektu. Aby uzyskać szczegółowe informacje, zobacz Set C++ compiler and build properties in Visual Studio (Ustawianie właściwości kompilatora języka C++ i kompilowania w programie Visual Studio).

  2. Wybierz stronę Właściwości>konfiguracji C/C++>Wiersza polecenia.

  3. Zmodyfikuj właściwość Opcje dodatkowe, aby uwzględnić/Zc:twoPhase-, a następnie wybierz przycisk OK.

Zobacz też

/Zc (Zgodność)