/Zc:ternary (Koşullu işleç kurallarını zorunlu kılma)

Bir koşullu işleç ifadesindeki ikinci ve üçüncü işlenenlerin türleri ve sabit veya geçici (cv) niteliği için C++ Standart kurallarının uygulanmasını etkinleştirin.

Sözdizimi

/Zc:ternary[-]

Açıklamalar

Visual Studio 2017'den başlayarak, derleyici C++ standart koşullu işleci (?:) davranışını destekler. Üçüncül işleç olarak da bilinir. C++ Standardı, üç koşuldan birini karşılayan üçüncül işlenenler gerektirir: İşlenenler aynı türde veya constvolatile nitelikte olmalıdır (cv-qualification) veya yalnızca bir işlenen kesin olarak diğerinin türüne ve cv yeterliliğine dönüştürülebilir olmalıdır. Öte yandan, işlenenlerden biri veya her ikisi de throw ifadesi olmalıdır. Visual Studio 2017 sürüm 15.5'in önceki sürümlerinde, derleyici standart tarafından belirsiz olarak kabul edilen dönüştürmelere izin verdi.

seçenek belirtildiğinde /Zc:ternary , derleyici standarda uyar. Eşleştirilen türler ve ikinci ve üçüncü işlenenlerin cv yeterliliği kurallarını karşılamayan kodu reddeder.

/Zc:ternary Visual Studio 2017'de seçenek varsayılan olarak kapalıdır. Uyumlu davranışı etkinleştirmek veya /Zc:ternary- önceki uyumsuz derleyici davranışını açıkça belirtmek için kullanın/Zc:ternary. /permissive- seçeneği bu seçeneği örtük olarak etkinleştirir, ancak kullanılarak /Zc:ternary-geçersiz kılınabilir.

Örnekler

Bu örnek, hem bir türden açık olmayan başlatma hem de türe dönüştürme sağlayan bir sınıfın belirsiz dönüştürmelere nasıl yol açabileceğini gösterir. Bu kod derleyici tarafından varsayılan olarak kabul edilir, ancak belirtildiğinde veya /permissive- belirtildiğinde /Zc:ternary reddedilir.

// zcternary1.cpp
// Compile by using: cl /EHsc /W4 /nologo /Zc:ternary zcternary1.cpp

struct A
{
   long l;
   A(int i) : l{i} {}    // explicit prevents conversion of int
   operator int() const { return static_cast<int>(l); }
};

int main()
{
   A a(42);
   // Accepted when /Zc:ternary (or /permissive-) is not used
   auto x = true ? 7 : a;  // old behavior prefers A(7) over (int)a
   auto y = true ? A(7) : a;   // always accepted
   auto z = true ? 7 : (int)a; // always accepted
   return x + y + z;
}

Bu kodu düzeltmek için, tercih edilen ortak türe açık bir tür ataması yapın veya bir tür dönüştürme yönünü engelleyin. Dönüştürmeyi açık hale getirerek derleyicinin bir tür dönüştürmesi ile eşleşmesini engelleyebilirsiniz.

İşlenenlerin türü, gibi const char16_t*null olarak sonlandırılan dize türlerinden const char*biri olduğunda, bu yaygın desen için önemli bir özel durumdur. Etkiyi dizi türleri ve çürümüş işaretçi türleriyle de yeniden oluşturabilirsiniz. için gerçek ikinci veya üçüncü işlenenin ?: karşılık gelen türde bir dize değişmez değeri olduğu davranış, kullanılan dil standardına bağlıdır. C++17, bu durumun semantiğini C++14 olarak değiştirdi. Sonuç olarak, derleyici aşağıdaki örnekteki kodu varsayılan /std:c++14altında kabul eder, ancak veya daha sonra belirttiğinizde /std:c++17 reddeder.

// zcternary2.cpp
// Compile by using: cl /EHsc /W4 /nologo /Zc:ternary /std:c++17 zcternary2.cpp

struct MyString
{
   const char * p;
   MyString(const char* s = "") noexcept : p{s} {} // from char*
   operator const char*() const noexcept { return p; } // to char*
};

int main()
{
   MyString s;
   auto x = true ? "A" : s; // MyString: permissive prefers MyString("A") over (const char*)s
}

Bu kodu düzeltmek için işlenenlerden birini açıkça yayınlayın.

altında /Zc:ternary, derleyici bağımsız değişkenlerden birinin türünde voidolduğu ve diğeri ifade throw olmayan koşullu işleçleri reddeder. Bu desenin yaygın bir kullanımı ASSERT benzeri makrolarda kullanılır:

// zcternary3.cpp
// Compile by using: cl /EHsc /W4 /nologo /Zc:ternary /c zcternary3.cpp

void myassert(const char* text, const char* file, int line);
#define ASSERT(ex) (void)((ex) ? 0 : myassert(#ex, __FILE__, __LINE__))
// To fix, define it this way instead:
// #define ASSERT(ex) (void)((ex) ? void() : myassert(#ex, __FILE__, __LINE__))

int main()
{
   ASSERT(false);  // C3447
}

Tipik çözüm, geçersiz olmayan bağımsız değişkeni ile void()değiştirmektir.

Bu örnek, hem /Zc:ternary-hem de /Zc:ternary altında hata oluşturan kodu gösterir:

// zcternary4.cpp
// Compile by using:
//   cl /EHsc /W4 /nologo /Zc:ternary zcternary4.cpp
//   cl /EHsc /W4 /nologo /Zc:ternary zcternary4.cpp

int main() {
   auto p1 = [](int a, int b) { return a > b; };
   auto p2 = [](int a, int b) { return a > b; };
   auto p3 = true ? p1 : p2; // C2593 under /Zc:ternary, was C2446
}

Bu kod daha önce şu hatayı verdi:

error C2446: ':': no conversion from 'foo::<lambda_f6cd18702c42f6cd636bfee362b37033>' to 'foo::<lambda_717fca3fc65510deea10bc47e2b06be4>'
note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

ile /Zc:ternaryhatanın nedeni daha net hale gelir. Her lambdayı oluşturmak için uygulama tanımlı çeşitli çağrı kurallarından herhangi biri kullanılabilir. Ancak, derleyicinin olası lambda imzalarını kesinleştirmeye yönelik bir tercih kuralı yoktur. Yeni çıkış şöyle görünür:

error C2593: 'operator ?' is ambiguous
note: could be 'built-in C++ operator?(bool (__cdecl *)(int,int), bool (__cdecl *)(int,int))'
note: or       'built-in C++ operator?(bool (__stdcall *)(int,int), bool (__stdcall *)(int,int))'
note: or       'built-in C++ operator?(bool (__fastcall *)(int,int), bool (__fastcall *)(int,int))'
note: or       'built-in C++ operator?(bool (__vectorcall *)(int,int), bool (__vectorcall *)(int,int))'
note: while trying to match the argument list '(foo::<lambda_717fca3fc65510deea10bc47e2b06be4>, foo::<lambda_f6cd18702c42f6cd636bfee362b37033>)'

tarafından /Zc:ternary bulunan yaygın bir sorun kaynağı, şablon meta programlamada kullanılan koşullu işleçlerden gelir. Bu anahtarın altındaki sonuç türlerinden bazıları değişir. Aşağıdaki örnekte, meta programlama olmayan bir bağlamda koşullu ifadenin sonuç türünü değiştiren iki durum /Zc:ternary gösterilmektedir:

// zcternary5.cpp
// Compile by using: cl /EHsc /W4 /nologo /Zc:ternary zcternary5.cpp

int main(int argc, char**) {
   char a = 'A';
   const char b = 'B';
   decltype(auto) x = true ? a : b; // char without, const char& with /Zc:ternary
   const char(&z)[2] = argc > 3 ? "A" : "B"; // const char* without /Zc:ternary
   return x > *z;
}

Tipik düzeltme, eski davranışı korumak için gereken sonuç türüne bir std::remove_reference özellik uygulamaktır.

Visual C++'daki uyumluluk sorunları hakkında daha fazla bilgi için bkz . Standart Dışı Davranış.

Bu derleyici seçeneğini Visual Studio geliştirme ortamında ayarlamak için

  1. Projenin Özellik Sayfaları iletişim kutusunu açın. Ayrıntılar için bkz . Visual Studio'da C++ derleyicisi ve derleme özelliklerini ayarlama.

  2. Yapılandırma Özellikleri>C/C++>Komut Satırı özellik sayfasını seçin.

  3. Ek Seçenekler özelliğini veya içerecek /Zc:ternary-/Zc:ternary şekilde değiştirin ve ardından Tamam'ı seçin.

Ayrıca bkz.

/Zc (Uyumluluk)