Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A C++ Standard szabályok érvényesítésének engedélyezése a második és harmadik operandus típusára és const vagy volatilis (cv) minősítésére egy feltételes operátorkifejezésben.
Szemantika
/Zc:ternary
[]-
Megjegyzések
A Visual Studio 2017-től kezdve a fordító támogatja a C++ standard feltételes operátor (?:
) viselkedését.
Ternáris operátorként is ismert. A C++ Standard megköveteli, hogy a ternáris operandusok megfeleljenek a három feltétel egyikének: Az operandusoknak azonos típusúnak és const
képesítésűnek volatile
kell lenniük (cv-minősítés), vagy csak az egyik operandus legyen egyértelműen átalakítható ugyanarra a típusra és a cv-minősítésre, mint a másikra. Vagy egy vagy mindkét operandusnak dobókifejezésnek kell lennie. A Visual Studio 2017 15.5-ös verziója előtti verziókban a fordító olyan átalakításokat engedélyezett, amelyeket a szabvány nem egyértelműnek tart.
Ha a /Zc:ternary
beállítás meg van adva, a fordító megfelel a szabványnak. Elutasítja azokat a kódot, amelyek nem felelnek meg a második és harmadik operandusok megfeleltetésének és cv-minősítésének.
A /Zc:ternary
beállítás alapértelmezés szerint ki van kapcsolva a Visual Studio 2017-ben. A megfelelő viselkedés engedélyezésére vagy /Zc:ternary
a korábbi nem megfelelő fordítói viselkedés explicit megadására használható/Zc:ternary-
. A /permissive-
beállítás implicit módon engedélyezi ezt a beállítást, de felül lehet bírálni a használatával /Zc:ternary-
.
Példák
Ez a minta azt mutatja be, hogy egy olyan osztály, amely nem explicit inicializálást biztosít egy típusból, és hogyan alakít át típusra, nem egyértelmű konverziókhoz vezethet. Ezt a kódot a fordító alapértelmezés szerint elfogadja, de a megadott vagy megadott esetben /Zc:ternary
/permissive-
elutasítja.
// 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;
}
A kód javításához hozzon létre egy explicit öntöttet az előnyben részesített általános típusra, vagy tiltsa le a típuskonverzió egyik irányát. A fordítás explicitvá tételével megtarthatja, hogy a fordító megfeleltethető legyen a típuskonverziónak.
Fontos kivétel ez alól a gyakori minta, ha az operandusok típusa az egyik null értékű sztringtípus, például const char*
, const char16_t*
és így tovább. Az effektust tömbtípusokkal és az általuk használt mutatótípusokkal is reprodukálhatja. Az a viselkedés, amikor a tényleges második vagy harmadik operandus ?:
egy megfelelő típusú sztringkonstans, a használt nyelvi szabványtól függ. A C++17 módosította az eset szemantikáját a C++14-ről. Ennek eredményeképpen a fordító elfogadja a következő példában szereplő kódot az alapértelmezett beállításnál /std:c++14
, de a megadott /std:c++17
vagy újabb beállításkor elutasítja azt.
// 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
}
A kód javításához az egyik operandust explicit módon kell leadnia.
Alatta /Zc:ternary
a fordító elutasítja azokat a feltételes operátorokat, amelyekben az egyik argumentum típusú void
, a másik pedig nem throw
kifejezés. Ennek a mintának a gyakori használata az ASSERT-szerű makrókban van:
// 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
}
A tipikus megoldás a nem érvénytelen argumentum lecserélése a következőre void()
: .
Ez a minta olyan kódot mutat be, amely hibát generál a következő és /Zc:ternary
a következő /Zc:ternary-
alatt:
// 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
}
Ez a kód korábban a következő hibát adta:
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
Ezzel /Zc:ternary
a hibával a hiba oka egyértelműbbé válik. Az egyes lambdák létrehozásához számos implementáció által definiált hívási konvenció használható. A fordító azonban nem rendelkezik olyan preferenciális szabállyal, amely egyértelműsíti a lehetséges lambda-aláírásokat. Az új kimenet a következőképpen néz ki:
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>)'
A problémák /Zc:ternary
gyakori forrása a sablon metaprogramozásában használt feltételes operátorok. A kapcsoló alatt az eredménytípusok némelyike megváltozik. Az alábbi példa két esetet mutat be, amikor /Zc:ternary
egy feltételes kifejezés eredménytípusát nem metaprogramozási környezetben módosítja:
// 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;
}
A tipikus javítás egy tulajdonság alkalmazása std::remove_reference
az eredménytípusra, ahol szükség van a régi viselkedés megőrzésére.
A Visual C++ kompatibilitási problémáival kapcsolatos további információkért lásd: Nem megfelelő viselkedés.
A fordító beállításának beállítása a Visual Studio fejlesztői környezetében
Nyissa meg a projekt Tulajdonságlapok párbeszédpanelt. További információ: C++ fordító és buildtulajdonságok beállítása a Visual Studio.
Válassza a Konfiguráció tulajdonságai>C/C++>parancssori tulajdonságlapját.
Módosítsa a További beállítások tulajdonságot a belefoglaláshoz
/Zc:ternary
, majd/Zc:ternary-
válassza az OK gombot.