共用方式為


/Zc:ternary (強制執行條件運算子規則)

針對條件運算子運算式中第二個和第三個運算元的類型和 const 或 volatile (cv) 限定性,啟用 C++ 標準規則的強制執行。

語法

/Zc:ternary[-]

備註

從 Visual Studio 2017 開始,編譯器支援 C++ 標準 條件運算子 ?: ) 行為。 也稱為三元運算子 。 C++ 標準需要三元運算元滿足三個條件之一:運算元的類型和 constvolatile 限定性 (cv-qualification), 或只有一個運算元必須明確轉換成與另一個類型相同的類型和 cv 資格。 或者,一或兩個運算元必須是 throw 運算式。 在 Visual Studio 2017 15.5 版之前的版本,編譯器允許將標準視為模棱兩可的轉換。

/Zc:ternary指定 選項時,編譯器符合標準。 它會拒絕不符合第二和第三個運算元之相符類型和 cv 限定性規則的程式碼。

在 Visual Studio 2017 中,此選項 /Zc:ternary 預設為關閉。 使用 /Zc:ternary 來啟用符合規範的行為,或 /Zc:ternary- 明確指定先前不符合規範的編譯器行為。 選項 /permissive- 會隱含地啟用這個選項,但可以使用 來覆寫 /Zc:ternary-

範例

此範例示範類別如何同時提供類型的非明確初始化,以及轉換成類型,可能會導致模棱兩可的轉換。 編譯器預設會接受此程式碼,但在指定 或 /permissive-/Zc:ternary 遭到拒絕。

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

若要修正此程式碼,請明確轉換成慣用的一般類型,或防止一個類型轉換方向。 您可以讓轉換明確,讓編譯器無法比對類型轉換。

此常見模式的重要例外狀況是運算元的類型是其中一個以 Null 終止的字串類型,例如 const char*const char16_t* 等等。 您也可以使用陣列類型及其衰變的指標類型來重現效果。 當 的實際第二個或第三個運算元 ?: 是對應型別的字串常值時的行為,取決於所使用的語言標準。 C++17 已從 C++14 變更此案例的語意。 因此,編譯器會接受下列範例中的程式 /std:c++14 代碼,但當您指定 /std:c++17 或更新版本時,會拒絕它。

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

若要修正此程式碼,請明確轉換其中一個運算元。

在 下 /Zc:ternary ,編譯器會拒絕條件運算子,其中其中一個引數的類型為 void ,而另一個 throw 則不是運算式。 此模式的常見用法是在類似 ASSERT 的宏中:

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

典型的解決方案是將非 void 引數取代為 void()

此範例示範在 和 /Zc:ternary-/Zc:ternary 產生錯誤的程式碼:

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

此程式碼先前已提供此錯誤:

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

使用 /Zc:ternary 時,失敗的原因會變得更清楚。 您可以使用數個實作定義的呼叫慣例來產生每個 Lambda。 不過,編譯器沒有喜好設定規則來厘清可能的 Lambda 簽章。 新的輸出看起來像這樣:

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>)'

找到 /Zc:ternary 的常見問題來源來自範本中繼程式設計中使用的條件運算子。 這個參數下的某些結果類型會變更。 下列範例示範兩種情況,其中 /Zc:ternary 在非中繼程式設計內容中變更條件運算式的結果類型:

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

典型的修正方式是在結果類型上套用 std::remove_reference 特性,而需要保留舊的行為。

如需 Visual C++ 中一致性問題的詳細資訊,請參閱 Nonstandard Behavior

在 Visual Studio 開發環境中設定這個編譯器選項

  1. 開啟專案的 [屬性頁] 對話方塊。 如需詳細資料,請參閱在 Visual Studio 中設定 C ++ 編譯器和組建屬性

  2. 選取 [組態屬性]>[C/C++]>[命令列] 屬性頁。

  3. 修改 [其他選項] 屬性以包含 /Zc:ternary/Zc:ternary- ,然後選擇 [ 確定 ]。

另請參閱

/Zc (一致性)