/ Zc: ternary (wymuszenie reguł operatora warunkowego)/Zc:ternary (Enforce conditional operator rules)

Włącz wymuszanie reguły C++ Standard dla typów i const lub volatile kwalifikacji (cv) drugiego i trzeciego operandu w wyrażeniu operator warunkowy.Enable enforcement of C++ Standard rules for the types and const or volatile (cv) qualification of the second and third operands in a conditional operator expression.

SkładniaSyntax

/ Zc: ternary[-]/Zc:ternary[-]

UwagiRemarks

Visual Studio w wersji 15.3 włączenie obsługi kompilatora C++ standardowy operator warunkowy (lub trójargumentowy) (?:) zachowanie.Visual Studio version 15.3 enables compiler support for C++ standard conditional (or ternary) operator (?:) behavior. C++ Standard wymaga argumentów tego samego typu i stałych nietrwałych kwalifikacji lub tylko jeden argument jako jednoznacznie konwertowane do tego samego typu i stałych nietrwałych kwalifikacji, co inne lub jeden lub obydwa operandy jako wyrażenie throw.The C++ Standard requires either the operands to be of the same type and cv-qualification, or for only one operand to be unambiguously convertible to the same type and cv-qualification as the other, or for one or both operands to be a throw expression. W wersjach starszych niż wersja 15.5 programu Visual Studio kompilator może konwersje, które są traktowane jako niejednoznaczny przez standard.In versions before Visual Studio version 15.5, the compiler allowed conversions that are considered ambiguous by the standard. Gdy /Zc: ternary opcja zostanie określona, kompilator jest zgodny ze standardem i odrzuca kod, który nie spełnia warunków reguły dla typów dopasowane i stałych nietrwałych kwalifikacji drugi i trzeci operand.When the /Zc:ternary option is specified, the compiler conforms to the standard and rejects code that does not satisfy the rules for matched types and cv-qualification of the second and third operands.

/Zc: ternary opcja jest domyślnie wyłączona.The /Zc:ternary option is off by default. Użyj /Zc: ternary Aby włączyć odpowiadające zachowanie lub /Zc:ternary- jawnie określić poprzednie zachowanie kompilatora niezgodnych.Use /Zc:ternary to enable conforming behavior, or /Zc:ternary- to explicitly specify the previous non-conforming compiler behavior. / Permissive- opcji niejawnie włączy tę opcję, ale może być zastąpiona przy użyciu /Zc:ternary-.The /permissive- option implicitly enables this option, but it can be overridden by using /Zc:ternary-.

PrzykładyExamples

Niniejszy przykład pokazuje, jak klasa, która zawiera zarówno inicjowania niejawnego typu i konwersji do typu może prowadzić do niejednoznaczne.This sample shows how a class that provides both non-explicit initialization from a type and conversion to a type can lead to ambiguous conversions. Ten kod jest akceptowany przez kompilator domyślnie, ale kiedy odrzucone /Zc: ternary lub / permissive- jest określony.This code is accepted by the compiler by default, but rejected when /Zc:ternary or /permissive- is specified.

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

Wymaganej poprawce jest dokonać jawnego rzutowania preferowany typ wspólny lub uniemożliwić jeden kierunek konwersji z uczestnictwa w polu wyszukiwania kompilatora dopasowanie typu, wprowadzając jawnej konwersji.The fix required is to make an explicit cast to the preferred common type, or prevent one direction of conversion from participation in the compiler search for a type match by making the conversion explicit.

Wyjątek ważne, aby ten typowy wzorzec jest, gdy typ operandu to jeden z typów ciąg zakończony znakiem null, takie jak const char*, const char16_t*i tak dalej.An important exception to this common pattern is when the type of the operands is one of the null-terminated string types, such as const char*, const char16_t*, and so on. Można również odtworzyć to typy tablic i typy wskaźników, które one decay do.You can also reproduce this with array types and the pointer types they decay to. Zachowanie podczas rzeczywistego drugi lub trzeci operand do?: jest odpowiedni typ literału ciągu jest zależna od standardowy język używany.The behavior when the actual second or third operand to ?: is a string literal of corresponding type depends on the language standard used. C ++ 17 zmianie uległa semantyki dla tego przypadku C ++ 14.C++17 has changed semantics for this case from C++14. W rezultacie kod w poniższym przykładzie jest akceptowany w obszarze /STD: c ++ 14 (domyślna wartość kompilatora), ale jest odrzucane, gdy /STD: c ++ 17 jest określony.As a result, the code in the following example is accepted under /std:c++14 (the compiler default) but is rejected when /std:c++17 is specified.

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

Aby rozwiązać ten kod, oddać jeden z argumentów jawnie.To fix this code, cast one of the operands explicitly.

W obszarze /Zc: ternary, operatorów warunkowych odrzutów kompilatora, gdy jeden z argumentów jest typu void, a druga nie jest wyrażeniem throw.Under /Zc:ternary, the compiler rejects conditional operators where one of the arguments is of type void and the other is not a throw expression. Typowym zastosowaniem tych znajduje się w makra ASSERT podobne:A common use of these is in ASSERT-like macros:

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

Typowym rozwiązaniem jest po prostu zastąpić argumentów niż void void().The typical solution is to simply replace the non-void argument with void().

W tym przykładzie przedstawiono kod, który generuje błąd w obu /Zc: ternary i /Zc:ternary-:This sample shows code that generates an error under both /Zc:ternary and /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
}

Ten kod wydał wcześniej ten błąd:This code previously gave this error:

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

Za pomocą /Zc: ternary przyczynę niepowodzenia staje się bardziej zrozumiały; w architekturach, gdzie dowolnego z kilku konwencji wywoływania zdefiniowanych w implementacji może służyć do generowania każdego lambda, kompilator określa Brak preferencji między nimi który można odróżnić podpisów możliwe lambda.With /Zc:ternary the reason for failure becomes clearer; on architectures where any of several implementation-defined calling conventions could be used to generate each lambda, the compiler expresses no preference among them that could disambiguate the possible lambda signatures. Nowe dane wyjściowe wyglądają następująco:The new output looks like this:

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

Wspólne źródło problemy związane z przyjęcia /Zc: ternary pochodzi z użycia operatora warunkowego w szablonie meta-programowania, jak zmienić się niektóre typy wyników w ramach tego przełącznika.A common source of problems related to adoption of /Zc:ternary comes from the use of the conditional operator in template meta-programming, as some of the result types change under this switch. W poniższym przykładzie pokazano dwa przypadki gdzie /Zc: ternary zmieni typ wyniku wyrażenia warunkowego, w kontekście meta programowania:The following example demonstrates two cases where /Zc:ternary changes a conditional expression’s result type in a non-meta-programming context:

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

Typowe rozwiązania w takich przypadkach polega na zastosowaniu std::remove_reference cech dla wyniku typu w przypadku, gdy spełnione, aby zachować stare zachowanie.The typical resolution in such cases is to apply a std::remove_reference trait on the result type where needed in order to preserve the old behavior.

Aby uzyskać więcej informacji na temat problemów ze zgodnością w języku Visual C++, zobacz niestandardowe zachowanie.For more information about conformance issues in Visual C++, see Nonstandard Behavior.

Aby ustawić tę opcję kompilatora w środowisku programowania Visual StudioTo set this compiler option in the Visual Studio development environment

  1. Otwórz projekt stron właściwości okno dialogowe.Open the project's Property Pages dialog box. Aby uzyskać więcej informacji, zobacz Praca z właściwościami projektu.For details, see Working with Project Properties.

  2. Wybierz właściwości konfiguracji > C/C++ > wiersza polecenia stronę właściwości.Select the Configuration Properties > C/C++ > Command Line property page.

  3. Modyfikowanie dodatkowe opcje właściwości do uwzględnienia /Zc: ternary lub /Zc:ternary- , a następnie wybierz OK.Modify the Additional Options property to include /Zc:ternary or /Zc:ternary- and then choose OK.

Zobacz takżeSee also

/Zc (Zgodność)/Zc (Conformance)