Bagikan melalui


/Zc:twoPhase- (nonaktifkan pencarian nama dua fase)

Opsi /Zc:twoPhase- , di bawah /permissive-, memberi tahu pengkompilasi untuk menggunakan perilaku kompilator Microsoft C++ asli yang tidak sesuai untuk mengurai dan membuat instans templat kelas dan templat fungsi.

Sintaks

/Zc:twoPhase-

Keterangan

Visual Studio 2017 versi 15.3 dan yang lebih baru: Di bawah /permissive-, pengkompilasi menggunakan pencarian nama dua fase untuk resolusi nama templat. Jika Anda juga menentukan /Zc:twoPhase-, pengkompilasi kembali ke templat kelas yang tidak sesuai sebelumnya dan resolusi dan perilaku penggantian nama templat fungsi. Ketika /permissive- tidak ditentukan, perilaku yang tidak sesuai adalah default.

File header Windows SDK dalam versi 10.0.15063.0 (Pembaruan Pembuat atau RS2) dan yang lebih lama tidak berfungsi dalam mode kesuaian. /Zc:twoPhase- diperlukan untuk mengkompilasi kode untuk versi SDK tersebut saat Anda menggunakan /permissive-. Versi Windows SDK yang dimulai dengan versi 10.0.15254.0 (Fall Creators Update atau RS3) berfungsi dengan benar dalam mode kesuaian. Mereka tidak memerlukan /Zc:twoPhase- opsi .

Gunakan /Zc:twoPhase- jika kode Anda memerlukan perilaku lama untuk dikompilasi dengan benar. Sangat mempertimbangkan untuk memperbarui kode Anda agar sesuai dengan standar.

Perilaku pengkompilasi di bawah /Zc:twoPhase-

Secara default, atau di Visual Studio 2017 versi 15.3 dan yang lebih baru saat Anda menentukan dan /permissive- /Zc:twoPhase-, pengkompilasi menggunakan perilaku ini:

  • Ini hanya mengurai deklarasi templat, kepala kelas, dan daftar kelas dasar. Isi templat diambil sebagai aliran token. Tidak ada badan fungsi, penginisialisasi, argumen default, atau argumen noexcept yang diurai. Templat kelas dibuat semu pada jenis tentatif untuk memvalidasi bahwa deklarasi dalam templat kelas sudah benar. Pertimbangkan templat kelas ini:

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

    Deklarasi templat, template <typename T>, kepala class Derivedkelas , dan daftar public Base<T> kelas dasar diurai, tetapi isi templat diambil sebagai aliran token.

  • Saat menguraikan templat fungsi, pengkompilasi hanya mengurai tanda tangan fungsi. Isi fungsi tidak pernah diurai. Sebagai gantinya, ini ditangkap sebagai aliran token.

Akibatnya, jika isi templat memiliki kesalahan sintaks, tetapi templat tidak pernah dibuat, pengompilasi tidak mendiagnosis kesalahan.

Efek lain dari perilaku ini adalah dalam resolusi kelebihan beban. Perilaku non-standar terjadi karena cara aliran token diperluas di situs instansiasi. Simbol yang tidak terlihat pada deklarasi templat mungkin terlihat pada titik instansiasi. Itu berarti mereka dapat berpartisipasi dalam resolusi kelebihan beban. Anda mungkin menemukan templat mengubah perilaku berdasarkan kode yang tidak terlihat pada definisi templat, bertentangan dengan standar.

Misalnya, pertimbangkan kode ini:

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

Berikut adalah output saat Anda menggunakan mode default, mode kesuaian, dan mode kesuaian dengan /Zc:twoPhase- opsi pengkompilasi:

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

Ketika dikompilasi dalam mode kesesuaian di bawah /permissive-, program ini mencetak "Standard two-phase", karena kelebihan beban func kedua tidak terlihat ketika pengkompilasi mencapai templat. Jika Anda menambahkan /Zc:twoPhase-, program mencetak "Microsoft one-phase". Outputnya sama seperti ketika Anda tidak menentukan /permissive-.

Nama dependen adalah nama yang bergantung pada parameter templat. Nama-nama ini memiliki perilaku pencarian yang juga berbeda di bawah /Zc:twoPhase-. Dalam mode kesamaan, nama dependen tidak terikat pada titik definisi templat. Sebaliknya, pengkompilasi mencarinya saat membuat instans templat. Untuk panggilan fungsi dengan nama fungsi dependen, nama terikat ke fungsi yang terlihat di situs panggilan dalam definisi templat. Kelebihan beban lain dari pencarian yang bergantung pada argumen ditambahkan, baik pada titik definisi templat, dan pada titik instansiasi templat.

Pencarian dua fase terdiri dari dua bagian: Pencarian untuk nama non-dependen selama definisi templat, dan pencarian untuk nama dependen selama instans templat. Di bawah /Zc:twoPhase-, pengkompilasi tidak melakukan pencarian dependen argumen secara terpisah dari pencarian yang tidak memenuhi syarat. Artinya, tidak melakukan pencarian dua fase, sehingga hasil resolusi kelebihan beban mungkin berbeda.

Berikut adalah contoh lain:

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

Ketika dikompilasi tanpa /permissive-, kode ini mencetak:

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

Ketika dikompilasi dengan /permissive-, tetapi tanpa /Zc:twoPhase-, kode ini mencetak:

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

Ketika dikompilasi dengan /permissive- dan /Zc:twoPhase-, kode ini mencetak:

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

Dalam mode kesesuaian di bawah /permissive-, panggilan tfunc(1729) diselesaikan ke void func(long) kelebihan beban. Ini tidak menyelesaikan void func(int) kelebihan beban, seperti di bawah /Zc:twoPhase-. Pasalnya, yang tidak memenuhi syarat func(int) dideklarasikan setelah definisi templat, dan tidak ditemukan melalui pencarian tergantung argumen. Tetapi void func(S) apakah berpartisipasi dalam pencarian tergantung argumen, sehingga ditambahkan ke kelebihan beban yang diatur untuk panggilan tfunc(s), meskipun dinyatakan setelah templat fungsi.

Perbarui kode Anda untuk kesuaian dua fase

Versi pengkompilasi yang lebih lama tidak memerlukan kata kunci template dan typename di mana pun C++ Standard memerlukannya. Kata kunci ini diperlukan dalam beberapa posisi untuk membedakan bagaimana kompilator harus mengurai nama dependen selama fase pertama pencarian. Contohnya:

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

Pengkompilasi yang sesuai diurai Foo sebagai variabel dalam lingkup T, yang berarti kode ini adalah logis-atau ekspresi dengan T::foo < a sebagai operand kiri dan b > (c) sebagai operand kanan. Jika Anda bermaksud menggunakan Foo sebagai templat fungsi, Anda harus menunjukkan bahwa itu adalah templat dengan menambahkan template kata kunci:

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

Dalam versi Visual Studio 2017 versi 15.3 dan yang lebih baru, ketika /permissive- dan /Zc:twoPhase- ditentukan, pengkompilasi memungkinkan kode ini tanpa template kata kunci. Ini menafsirkan kode sebagai panggilan ke templat fungsi dengan argumen a || b, karena hanya mengurai templat dengan cara terbatas. Kode di atas tidak diurai sama sekali pada fase pertama. Selama fase kedua, ada cukup konteks untuk memberi tahu bahwa T::Foo itu adalah templat daripada variabel, sehingga pengkompilasi tidak memberlakukan penggunaan kata kunci.

Perilaku ini juga dapat dilihat dengan menghilangkan kata kunci typename sebelum nama dalam badan templat fungsi, penginisialisasi, argumen default, dan argumen noexcept. Contohnya:

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

Jika Anda tidak menggunakan kata kunci typename dalam isi fungsi, kode ini dikompilasi di bawah /permissive- /Zc:twoPhase-, tetapi tidak di bawah /permissive- sendirian. Kata typename kunci diperlukan untuk menunjukkan bahwa TYPE dependen. Karena isi tidak diurai di bawah /Zc:twoPhase-, pengkompilasi tidak memerlukan kata kunci. Dalam /permissive- mode kesuaian, kode tanpa typename kata kunci menghasilkan kesalahan. Untuk memigrasikan kode Anda agar sesuai di Visual Studio 2017 versi 15.3 dan seterusnya, sisipkan typename kata kunci tempat kode hilang.

Demikian pula, pertimbangkan sampel kode ini:

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

Di bawah /permissive- /Zc:twoPhase- dan di kompilator yang lebih lama, pengkompilasi hanya memerlukan template kata kunci pada baris 2. Dalam mode kesuaian template , pengkompilasi sekarang juga memerlukan kata kunci pada baris 4 untuk menunjukkan bahwa T::X<T> itu adalah templat. Cari kode yang tidak memiliki kata kunci ini, dan berikan agar kode Anda sesuai dengan standar.

Untuk informasi selengkapnya tentang masalah kesuaian, lihat Peningkatan kesuaian C++ di Visual Studio dan Perilaku nonstandar.

Untuk mengatur opsi pengkompilasi ini di lingkungan pengembangan Visual Studio

  1. Buka kotak dialog Halaman Properti proyek. Untuk detailnya, lihat Mengatur pengkompilasi C++ dan membuat properti di Visual Studio.

  2. Pilih halaman properti Properti>Konfigurasi C/C++>Baris Perintah.

  3. Ubah properti Opsi Tambahan untuk disertakan /Zc:twoPhase- lalu pilih OK.

Lihat juga

/Zc (Kesuaian)