Megosztás a következőn keresztül:


A C++ megfelelőség fejlesztései, viselkedésváltozásai és hibajavításai a Visual Studio 2022-ben

A Microsoft C/C++ a Visual Studióban (MSVC) minden kiadásban továbbfejleszti a megfelelőséget és a hibajavításokat. Ez a cikk a jelentős fejlesztéseket sorolja fel fő kiadás, majd verzió szerint. Ha közvetlenül egy adott verzió módosításaira szeretne ugrani, használja az Ebben a cikkben hivatkozásokat a cikk tetején.

Ez a dokumentum a Visual Studio 2022 változásait sorolja fel.

A Visual Studio korábbi verzióinak változásai:

Verzió Megfelelőségi fejlesztések linkje
2019 C++ kompatibilitási fejlesztések a Visual Studio 2019-ben
2017 C++ megfelelőségi fejlesztések a Visual Studio 2017
2003-2015 Visual C++ Újdonságok 2003–2015

Megfelelőségi fejlesztések a Visual Studio 2022 17.14-es verziójában

A Visual Studio 2022 17.14-es verziója az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

Megfelelőségi fejlesztések

  • A standard könyvtár megerősítése (P3471R4) a standard könyvtár néhány nem definiált viselkedési esetét átalakítja __fastfail hívássá. Alapértelmezés szerint ki van kapcsolva. Projektszintű _MSVC_STL_HARDENING=1 engedélyezés definiálása.

Továbbfejlesztett viselkedés

  • "Destruktor-sírkövek" implementálása a használat utáni hibák enyhítésére. Alapértelmezés szerint ki van kapcsolva. Projektszintű _MSVC_STL_DESTRUCTOR_TOMBSTONES=1 engedélyezés definiálása.

Hibajavítások

  • Kijavítottuk a hibás fordítóhibákat, amelyek a <format> használatakor léptek fel CUDA-projektben.

  • Kijavítottunk egy fordító hibát, amely miatt egy helyi változó címe "kiszivároghatott" a kiértékelés során constexpr . Például:

    const unsigned & func() 
    {
      const int x = 0;
      constexpr const unsigned & r1 = x; // Previously accepted, now an error
      return r1;
    }
    
    auto r = func();  // Previously, the local address leaked
    

    Példa 2.

    #include <initializer_list>
    
    void test()
    {
        constexpr std::initializer_list<int> xs { 1, 2, 3 };        // Previously accepted, now an error
    
        static constexpr std::initializer_list<int> ys { 1, 2, 3 }; // Correct usage - note use of static
    }
    
  • A /permissive- kóddal fordított program már nem fogadja el a friend és static kombinációját a deklarációkban. A javítás általában az static eltávolítása a deklarációból. Például:

    struct S
    {
        friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend'
    };
    
  • Referenciakötés az alap- vagy származtatott osztályra való hivatkozáskor rögzített illékony minősítésű típusokhoz. Például:

    struct A {};
    struct B : public A {};
    
    void f(A&);                 // 1
    void f(const volatile A&);  // 2
    
    f(B{}); // Previously called 2. This is ill-formed under /permissive- or /Zc:referenceBinding. Chooses 1 if relaxed reference binding rules are enabled.
    

A standard sablontár módosításainak részletes összefoglalásáért, beleértve a megfelelőségi módosításokat, a hibajavításokat és a teljesítménybeli fejlesztéseket, tekintse meg az STL Changelog VS 2022 17.14-et.

Megfelelőségi fejlesztések a Visual Studio 2022 17.13-ás verziójában

A Visual Studio 2022 17.13-es verziója a Microsoft C/C++ fordítóban az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza.

A standard sablontár módosításainak részletes összefoglalásáért, beleértve a megfelelőség változásait, a hibajavításokat és a teljesítménybeli fejlesztéseket, tekintse meg STL Changelog VS 2022 17.13.

Argumentumfüggő keresés (ADL)

A nyelvi szerkezetek, például a tartomány és a strukturált kötések speciális argumentumfüggő keresési szabályokkal rendelkeznek bizonyos azonosítókhoz, például begin, endvagy get. Korábban ez a keresés jelölteket is tartalmazott a std névtérből, még akkor is, ha a névtér std nem része az argumentumfüggő kereséshez társított névterek szokásos készletének.

Azok a programok, amelyek ezekhez a szerkezetekhez vezették be a deklarációkat az std-hoz, már nem fordíthatók le. Ehelyett a deklarációknak normál társított névtérben kell lenniük az érintett típusokhoz (esetleg a globális névteret is beleértve).

template <typename T>
struct Foo {};

namespace std
{
    // To correct the program, move these declarations from std to the global namespace
    template <typename T>
    T* begin(Foo<T>& f);
    template <typename T>
    T* end(Foo<T>& f);
}

void f(Foo<int> foo)
{
   for (auto x : foo) // Previously compiled. Now emits error C3312: no callable 'begin' function found for type 'Foo<int>'
   {
      ...
   }
}

A implementáció által fenntartott makrók nem módosíthatók

Korábban a fordító engedélyezte bizonyos implementáció által biztosított makrók, például a _MSC_EXTENSIONSmódosítását vagy törlését. Bizonyos makrók definíciójának módosítása nem definiált viselkedést eredményezhet.

Bizonyos fenntartott makrónevek módosításának vagy meghatározatlanná tételének megkísérlése mostantól, az 1. szintű figyelmeztetést eredményezi C5308. /permissive- módban a rendszer hibaként kezeli ezt a figyelmeztetést.

#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior

Megfelelőségi fejlesztések a Visual Studio 2022 17.12-es verziójában

A Visual Studio 2022 17.12-es verziója az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

A standard sablontár módosításainak részletes összefoglalásáért, beleértve a megfelelőség változásait, a hibajavításokat és a teljesítménybeli fejlesztéseket, tekintse meg STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() mostantól explicit

Ez egy forrás/bináris kompatibilitástörő változás.

Az bool példányok _com_ptr_t-vá való implicit konvertálása meglepő lehet, és fordítási hibákhoz is vezethet. C.164: Kerülje az implicit konverziós operátorokat a C++ alapvető irányelvekben, amelyek elutasítják az implicit konverziós függvényeket. _com_ptr_t implicit konverziókat tartalmazott mind bool-re, mind Interface*-re. Ez a két implicit konverzió kétértelműséghez vezethet.

A probléma megoldásához a konvertálás bool explicit lesz. A konvertálás Interface*-ra nem változik.

A rendszer egy makrót biztosít, amely letiltja ezt az új viselkedést, és visszaállítja az előző implicit konverziót. Fordítson /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL a változás elkerüléséhez. Javasoljuk, hogy módosítsa a kódot úgy, hogy ne támaszkodjon implicit konverziókra.

Például:

#include <comip.h>

template<class Iface>
using _com_ptr = _com_ptr_t<_com_IIID<Iface, &__uuidof(Iface)>>;

int main()
{
   _com_ptr<IUnknown> unk;
   if (unk) // Still valid
   { 
      // ...
   }
   bool b = unk; // Still valid.
   int v = unk; // Previously permitted, now emits C2240: cannot convert from '_com_ptr_t<_com_IIID<IUnknown,& _GUID_00000000_0000_0000_c000_000000000046>>' to 'int'
}

Az állandó kifejezések már nem mindig noexcept értékűek megengedő módban.

Ez egy forrás/bináris kompatibilitástörő változás.

A konstans kifejezés mindig noexceptvolt, még akkor is, ha tartalmazott egy függvényhívást egy olyan függvényhez, amelyet egy kivételspecifikációt tartalmazóan deklaráltak. Ezt a szöveget a C++17-ben eltávolítottuk, bár a Microsoft Visual C++ fordító továbbra is /permissive módban támogatta az összes C++ nyelvi verzióban.

Ez a /permissive mód viselkedése el lesz távolítva. Az állandó kifejezések már nem kapnak speciális implicit viselkedést.

A noexcept függvények constexpr-meghatározása mostantól minden módban tiszteletben van tartva. Ez a módosítás szükséges a normál noexcept viselkedésre támaszkodó, későbbi alapvető problémamegoldások helyes végrehajtásához.

Például:

constexpr int f(bool b) noexcept(false)
{ 
    if (b)
    {
        throw 1;
    }
    else
    {
        return 1;
    }
}

void g(bool b)
{
   noexcept(f(b)); // false. No change to behavior
   noexcept(f(true)); // false. No change to behavior
   noexcept(f(false)); // false. Was true in /permissive mode only in previous versions.
}

Megfelelőségi fejlesztések a Visual Studio 2022 17.11-es verziójában

A Visual Studio 2022 17.11-es verziója az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

A standard sablontár módosításainak részletes összefoglalásáért, beleértve a megfelelőségi módosításokat, a hibajavításokat és a teljesítménybeli fejlesztéseket, tekintse meg STL Changelog VS 2022 17.11.

A P3142R0 szerint mostantól egyszerűen létrehozhat egy üres sort println. Ez a funkció a /std:c++latest összeállításakor érhető el. A módosítás előtt a következőt írta: println(""); Most írja: println();.

  • println(); egyenértékű a println(stdout);
  • println(FILE* stream); egyenértékű a println(stream, "\n");

Megvalósítva range_formatter

A P2286R8range_formatter már implementálva van. Ez a funkció a /std:c++latest összeállításakor érhető el.

Megfelelőségi fejlesztések a Visual Studio 2022 17.10-es verziójában

A Visual Studio 2022 17.10-es verziója az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

A standard sablontár módosításainak részletes összefoglalásáért, beleértve a megfelelőségi módosításokat, a hibajavításokat és a teljesítménybeli fejlesztéseket, tekintse meg STL Changelog VS 2022 17.10.

Konverziós operátor specializáció kifejezetten megadott visszatérési típussal

A fordító bizonyos esetekben helytelenül specializálta a konverziós operátorokat, ami eltérő visszatérési típushoz vezethet. Ezek az érvénytelen specializációk már nem fordulnak elő. Ez egy forráskódot megtörő változtatás.

// Example 1
struct S
{
    template<typename T> operator const T*();
};

void test()
{
    S{}.operator int*(); // this is invalid now
    S{}.operator const int*(); // this is valid
}
// Example 2
// In some cases, the overload resolution result may change
struct S
{
    template <typename T> operator T*(); // overload 1
    template <typename T> operator const T*(); // overload 2
};

void test()
{
    S{}.operator int*(); // this used to call overload 2, now it calls overload 1
}

#elifdef és #elifndef támogatása hozzáadva

Hozzáadták a támogatást a WG21 P2334R1 (C++23) és a WG14 N2645 (C++23) számára, amelyek bevezették a #elifdef és #elifndef előfeldolgozási irányelveket. /std:clatest vagy /std:c++latestszükséges.

Előtt:

#ifdef __cplusplus
  #include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

Után:

#ifdef __cplusplus
  #include <atomic>
#elifndef __STDC_NO_ATOMICS__
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

A _Alignas alkalmazása strukturált típuson C-ben

A C nyelvre (C17 és újabb verziók) vonatkozik. A Microsoft Visual Studio 17.9-hez is hozzáadva

A Visual Studio 2022 17.9-es verziója előtti Visual C++ verziókban, ha a _Alignas-azonosító egy strukturált típus mellett jelent meg egy deklarációban, akkor a ISO-C Standard szerint nem lett megfelelően alkalmazva.

// compile with /std:c17
#include <stddef.h>

struct Outer
{
    _Alignas(32) struct Inner { int i; } member1;
    struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");

Az ISO-C Standard szerint ezt a kódot úgy kell lefordítani, hogy ne bocsásson ki static_assert hibaüzenetet.

A _Alignas irányelv csak az member1tagváltozóra vonatkozik. Nem módosíthatja struct Inner igazítását. A Visual Studio 17.9.1 előtt azonban a "helytelen igazítás" diagnosztika megjelent. A fordító a member2-t a struct Outer típuson belül 32 bájtos eltolásra illesztette.

Ez egy bináris kompatibilitástörő változás, ezért a módosítás érvénybe lépésekor figyelmeztetés jelenik meg. A C5274 figyelmeztetés most az 1. figyelmeztetési szinten van kibocsátva az előző példában: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

Emellett a Visual Studio korábbi verzióiban, amikor a _Alignas-azonosító egy névtelen típusdeklaráció mellett jelent meg, figyelmen kívül hagyta.

// compile with /std:c17
#include <stddef.h>
struct S
{
    _Alignas(32) struct { int anon_member; };
    int k;
};

static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");

Korábban mindkét static_assert utasítás sikertelen volt a kód összeállításakor. Most a kód lefordul, de a következő 1. szintű figyelmeztetéseket bocsát ki:

warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)

Az előző viselkedés lekéréséhez cserélje le _Alignas(N)__declspec(align(N)). A _Alignasellentétben declspec(align) a típusra vonatkozik.

Továbbfejlesztett figyelmeztetés C4706

Ez egy forráskódot megtörő változtatás. Korábban a fordító nem észlelte a hozzárendelés zárójelben való körbefuttatásának konvencióját, ha a hozzárendelés célja az volt, hogy letiltsa C4706 figyelmeztetést, a feltételes kifejezésen belüli hozzárendeléssel kapcsolatban. A fordító ekkor felismeri a zárójeleket, és letiltja a figyelmeztetést.

#pragma warning(error: 4706)

struct S
{
   auto mf()
   {
      if (value = 9)
         return value + 4;
      else
         return value;
   }

   int value = 9;
};

A fordító ekkor a figyelmeztetést is kibocsátja olyan esetekben, amikor a függvény nem hivatkozik rá. Korábban, mivel a mf egy nem hivatkozott beágyazott függvény, a C4706 figyelmeztetés nem lett kibocsátva ehhez a kódhoz. Most a következő figyelmeztetést adja ki:

error C4706: assignment used as a condition
note: if an assignment is intended you can enclose it in parentheses, '(e1 = e2)', to silence this warning

A figyelmeztetés kijavításához használjon egyenlőség operátort, value == 9, ha ez a szándékának megfelelő. Vagy a hozzárendelést zárójelek közé helyezheti, (value = 9), ha hozzárendelést szán. Máskülönben, mivel a függvény nincs hivatkozva, távolítsa el.

Megfelelőségi fejlesztések a Visual Studio 2022 17.9-es verziójában

A Visual Studio 2022 17.9-es verziója a Következő megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

A standard sablontár módosításainak szélesebb körű összefoglalását lásd STL Changelog VS 2022 17.9.

A _Alignas alkalmazása strukturált típuson C-ben

A Visual C++ Visual Studio 2022 17.9-es verziója előtti verzióiban, amikor _Alignas egy deklarációban egy struktúratípus mellett jelent meg, a ISO-C Standard szerint nem lett megfelelően alkalmazva. Például:

// compile with /std:c17
#include <stddef.h>
struct Outer
{
    _Alignas(32) struct Inner { int i; } member1;
    struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");

A ISO-C Standard szerint ennek a kódnak le kell fordulnia anélkül, hogy a static_assert diagnosztikát bocsátana ki. A _Alignas irányelv csak az member1tagváltozóra vonatkozik. Nem módosíthatja struct Inner igazítását. A Visual Studio 17.9.1-es kiadása előtt azonban a "helytelen igazítás" diagnosztikai üzenetet adta ki. A fordító a member2-t egy 32 bájtos eltoláshoz igazította a struct Outer-en belül.

A hiba kijavítása bináris kompatibilitástörő változás, ezért a viselkedésváltozás alkalmazásakor figyelmeztetés jelenik meg. Az előző kódnál a C5274 sz. figyelmeztetés, "_Alignas már nem vonatkozik az 'Inner' típusra (csak deklarált adatobjektumokra vonatkozik)", most az 1-es szintű figyelmeztetések között kerül kibocsátásra.

A Visual Studio korábbi verzióiban _Alignas figyelmen kívül lett hagyva, amikor egy névtelen típusdeklaráció mellett jelent meg. Például:

// compile with /std:c17
#include <stddef.h>
struct S {
    _Alignas(32) struct { int anon_member; };
    int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");

Korábban mindkét static_assert utasítás sikertelen volt a kód összeállításakor. A kód most már lefordítva van, de az alábbi 1. szintű figyelmeztetésekkel:

warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)

Ha a korábbi viselkedést szeretné, cserélje le _Alignas(N)__declspec(align(N)). A _Alignasellentétben declspec(align) alkalmazható egy típusra.

Az __VA_OPT__ bővítményként van engedélyezve a /Zc:preprocessor alatt

__VA_OPT__ a C++20 és a C23 csomaghoz lett hozzáadva. A hozzáadását megelőzően nem volt szabványos módszer a vessző kihagyására variadikus makrókban. A jobb hátrameneti kompatibilitás érdekében a __VA_OPT__ a token alapú előfeldolgozó /Zc:preprocessor alatt minden nyelvi verzióban engedélyezve van.

Ez például hiba nélkül fordítja le a következőt:

#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))

// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")

C23 nyelv

C23 esetén a /std:clatest fordítókapcsoló használatakor a következők érhetők el:

typeof
typeof_unqual

Az alábbiak minden C nyelvi verzióhoz elérhetők:

__typeof__
__typeof_unqual__

C++ szabványos könyvtár

C++23 funkciók

  • formattable, range_format, format_kindés set_debug_format() a P2286R8 formázási tartományok részeként
  • <mdspan> per P0009R18 és a C++23 Standardhoz alkalmazott további szövegmódosítások.
  • format() mutatók P2510R3 szerint.

Megfelelőségi fejlesztések a Visual Studio 2022 17.8-ás verziójában

A Visual Studio 2022 17.8-s verziója a Microsoft C/C++ fordítóban az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza.

/FU hibát okoz

A C fordító elfogadta a /FU lehetőséget, annak ellenére, hogy egy ideje nem támogatja a felügyelt fordítást. Most hibát ad ki. Az ezt a lehetőséget átadó projekteknek csak C++/CLI-projektekre kell korlátozniuk.

C++ szabványos könyvtár

A C++23 elnevezett modulok, std és std.compat, már elérhetők a /std:c++20fordításakor.

A C++ standard kódtár módosításainak szélesebb körű összefoglalásáért lásd STL Changelog VS 2022 17.8.

Megfelelőségi fejlesztések a Visual Studio 2022 17.7-es verziójában

A Visual Studio 2022 17.7-es verziója a Microsoft C/C++ fordítóban az alábbi kiemelt megfelelőségi fejlesztéseket, hibajavításokat és viselkedésbeli változásokat tartalmazza.

Hozzáadott /std:clatest a C fordítóhoz

Ez a kapcsoló a C++ fordító /std:c++latest kapcsolójához hasonlóan viselkedik. A kapcsoló lehetővé teszi a jelenleg implementált fordító és a következő C szabványhoz javasolt standard kódtár-funkciókat, valamint néhány folyamatban lévő és kísérleti funkciót.

C++ szabványos könyvtár

A <print> könyvtár mostantól támogatott. Lásd P2093R14 Formázott kimeneti.

Megvalósítva views::cartesian_product.

A standard sablontár módosításainak szélesebb körű összefoglalását lásd STL Changelog VS 2022 17.7.

using megfelelőség

Korábban a using irányelv miatt a használt névterek nevei akkor is láthatók maradnak, ha nem kellene. Ez azt eredményezheti, hogy a nem minősített névkeresés akkor is megkeresi a nevet egy névtérben, ha nincs aktív using irányelv.

Íme néhány példa az új és a régi viselkedésre.
Az alábbi megjegyzésekben az "(1)" hivatkozások azt jelentik, hogy a f<K>(t) hívása történik a Anévtérben.

namespace A
{ 
    template<typename K, typename T> 
    auto f2(T t)
    { 
        return f<K>(t); // (1) Unqualified lookup should not find anything
    } 
} 

namespace B
{ 
    template<typename K, typename T> 
    auto f(T t) noexcept
    { // Previous behavior: This function was erroneously found during unqualified lookup at (1)
        return A::f2<K>(t); 
    } 
} 

namespace C
{ 
    template<typename T> 
    struct S {}; 

    template<typename, typename U> 
    U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function 
} 

namespace D
{ 
    using namespace B; 

    void h()
    { 
        D::f<void>(C::S<int>()); 
    } 
} 

Ugyanez a mögöttes probléma a korábban lefordított kód elutasítását okozhatja:

#include <memory>
namespace Addin {}
namespace Gui
{
    using namespace Addin;
}

namespace Addin
{
    using namespace std;
}

// This previously compiled, but now emits error C2065 for undeclared name 'allocator'.
// This should be declared as 'std::allocator<T*>' because the using directive nominating
// 'std' is not active at this point.
template <class T, class U = allocator<T*>>
class resource_list
{
};

namespace Gui
{
    typedef resource_list<int> intlist;
}

Megfelelőségi fejlesztések a Visual Studio 2022 17.6-os verziójában

A Visual Studio 2022 17.6-os verziója a Microsoft C/C++ fordítóban az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza.

Az volatile összetett hozzárendelések már nem számítanak elavultnak.

A C++20 elavulttá tette bizonyos operátorok alkalmazását a volatileminősített típusokra. Ha például a következő kód cl /std:c++20 /Wall test.cppvan lefordítva:

void f(volatile int& expr)
{
   ++expr;
}

A fordító állítja elő a test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20-t.

A C++20-ban az összetett hozzárendelési operátorok (@=űrlap operátorai) elavultak. A C++23-ban a C++20-ban kiküszöbölt összetett operátorok már nem minősülnek elavultnak. A C++23-ban például a következő kód nem hoz létre figyelmeztetést, míg a C++20-ban:

void f(volatile int& e1, int e2)
{
   e1 += e2;
}

További információ a módosításról: CWG:2654

Kevésbé jelent nagyobb változást a kifejezések egyenlőségének újraírása (P2468R2)

A C++20-ban P2468R2 módosította a fordítót úgy, hogy elfogadja a következő kódot:

struct S
{
    bool operator==(const S&);
    bool operator!=(const S&);
};
bool b = S{} != S{};

A fordító elfogadja ezt a kódot, ami azt jelenti, hogy a fordító szigorúbb a következő kóddal:

struct S
{
  operator bool() const;
  bool operator==(const S&);
};

bool b = S{} == S{};

A fordító 17.5-ös verziója elfogadja ezt a programot. A fordító 17.6-os verziója elutasítja. A hiba kijavításához adja hozzá a const-t a operator==-hez, hogy eltávolítsa a kétértelműséget. Vagy adjon hozzá egy megfelelő operator!= a definícióhoz az alábbi példában látható módon:

struct S
{
  operator bool() const;
  bool operator==(const S&);
  bool operator!=(const S&);
};

bool b = S{} == S{};

A Microsoft C/C++ fordító 17.5-ös és 17.6-os verziói elfogadják az előző programot, és mindkét verzióban meghívják S::operator==.

A P2468R2 felvázolt általános programozási modell az, hogy ha egy típushoz megfelelő operator!= van, az általában letiltja az újraírási viselkedést. A C++17-ben korábban lefordított kód javasolt javítása a megfelelő operator!= hozzáadása. További információ: programozási modell.

Megfelelőségi fejlesztések a Visual Studio 2022 17.4-es verziójában

A Visual Studio 2022 17.4-es verziója a Következő megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

A hatókör nélküli enum mögöttes típusai rögzített típus nélkül

A Visual Studio 2022 17.4-es verziója előtti Visual Studio-verziókban a C++ fordító nem határozta meg helyesen a rögzített alaptípus nélküli, nem rögzített enumerálás mögöttes típusát. Az /Zc:enumTypesalatt most már helyesen implementáljuk a standard viselkedést.

A C++ Standard megköveteli, hogy egy enum alapjául szolgáló típus elég nagy legyen ahhoz, hogy az adott enumminden enumerátort tároljon. A kellően nagy enumerátorok a enum mögöttes típusát unsigned int, long longvagy unsigned long longértékre állíthatják . Korábban ezeknek a enum-típusoknak mindig int volt az alaptípusuk a Microsoft fordítójában, függetlenül az enumerátor értékeitől.

Ha engedélyezve van, a /Zc:enumTypes lehetőség egy lehetséges forrás- és bináris kompatibilitást törő változásra ad lehetőséget. Alapértelmezés szerint ki van kapcsolva, és a /permissive-nem engedélyezi, mert a javítás hatással lehet a bináris kompatibilitásra. Egyes enumerálási típusok akkor változtatják meg a méretet, ha a megfelelő javítás engedélyezve van. Egyes Windows SDK-fejlécek tartalmazzák az ilyen számbavételi definíciókat.

Példa

enum Unsigned
{
    A = 0xFFFFFFFF // Value 'A' does not fit in 'int'.
};

// Previously, failed this static_assert. Now passes with /Zc:enumTypes.
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);

template <typename T>
void f(T x)
{
}

int main()
{
    // Previously called f<int>, now calls f<unsigned int>.
    f(+A);
}

// Previously this enum would have an underlying type of `int`, but Standard C++ requires this to have
// a 64-bit underlying type. Using /Zc:enumTypes changes the size of this enum from 4 to 8, which could
// impact binary compatibility with code compiled with an earlier compiler version or without the switch.
enum Changed
{
    X = -1,
    Y = 0xFFFFFFFF
};

Az enum definícióban szereplő enumerátorok típusai rögzített mögöttes típus nélkül

A Visual Studio 2022 17.4-es verziója előtti Visual Studio-verziókban a C++ fordító nem modellezte helyesen az enumerátorok típusait. Az enumeráció zárójele előtt nem megfelelő típust vehet fel egy rögzített mögöttes típus nélküli felsorolásban. A /Zc:enumTypesalatt a fordító most már helyesen implementálja a standard viselkedést.

A C++ Standard azt határozza meg, hogy a rögzített mögöttes típus nélküli enumerálási definícióban az inicializálók határozzák meg az enumerátorok típusait. Vagy az inicializáló nélküli enumerátorok esetében az előző enumerátor típusa szerint (a túlcsordulás elszámolása). Korábban az ilyen enumerátorok mindig az enumeráció dedukált típusát kapták, ahol a mögöttes típus általában helyőrzőként volt feltüntetve (int).

Ha engedélyezve van, a /Zc:enumTypes lehetőség egy lehetséges forrás- és bináris kompatibilitást törő változásra ad lehetőséget. Alapértelmezés szerint ki van kapcsolva, és a /permissive-nem engedélyezi, mert a javítás hatással lehet a bináris kompatibilitásra. Egyes enumerálási típusok akkor változtatják meg a méretet, ha a megfelelő javítás engedélyezve van. Egyes Windows SDK-fejlécek tartalmazzák az ilyen számbavételi definíciókat.

Példa

enum Enum {
    A = 'A',
    B = sizeof(A)
};

static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes

Ebben a példában az enumerátor A-nak a char típusú kell lennie az enumeráció záró kapcsos zárójele előtt, ezért B-t a sizeof(char)használatával kell inicializálni. A /Zc:enumTypes javítása előtt a A enumerálási típusa Enum volt, amelyből származtatott alapértelmezett típusra lett következtetve int, és a B inicializálása a sizeof(Enum) vagy 4 használatával történt.

Megfelelőségi fejlesztések a Visual Studio 2022 17.3-s verziójában

A Visual Studio 2022 17.3-s verziója a Microsoft C/C++ fordítóban az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza.

C: Továbbfejlesztett módosító kompatibilitás ellenőrzése a mutatók között

A C fordító nem hasonlítja össze megfelelően a módosítókat a mutatók között, különösen void*. Ez a hiba a const int** és void* közötti inkompatibilitás helytelen diagnosztizálását, valamint a int* volatile* és void*közötti kompatibilitás diagnosztizálását eredményezheti.

Példa

void fn(void* pv) { (pv); }

int main()
{
    int t = 42;
    int* pt = &t;
    int* volatile * i = &pt;
    fn(i);    // Now raises C4090
    const int** j = &pt;
    fn(j);    // No longer raises C4090
}

Megfelelőségi fejlesztések a Visual Studio 2022 17.2-es verziójában

A Visual Studio 2022 17.2-es verziója a Következő megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

Nem definiált kétirányú karakterekkel kapcsolatos figyelmeztetések

A Visual Studio 2022 17.2-es verziója bevezet egy 3. szintű figyelmeztetést, a C5255-öt, a megjegyzésekben és sztringekben található befejezetlen Unicode kétirányú karakterekre vonatkozóan. A figyelmeztetés a trójai forrás: Láthatatlan biztonsági rések Nicholas Boucher és Ross Anderson által leírt biztonsági problémákra vonatkozik. További információ a Unicode kétirányú karakterekről: Unicode® standard melléklet #9: UNICODE BIDIRECTIONAL ALGORITHM.

A C5255 figyelmeztetés csak azokat a fájlokat kezeli, amelyek konvertálás után Unicode kétirányú karaktereket tartalmaznak. Ez a figyelmeztetés az UTF-8, UTF-16 és UTF-32 fájlokra vonatkozik, ezért meg kell adni a megfelelő forráskódolást. Ez a változás egy forrástörő változás.

Példa (előtte/utána)

A Visual Studio 2022 17.2-es verziója előtt, a nem lezárt kétirányú karakter nem adott figyelmeztetést. A Visual Studio 2022 17.2-es verziója c5255-ös figyelmeztetést állít elő:

// bidi.cpp
int main() {
    const char *access_level = "user";
    // The following source line contains bidirectional Unicode characters equivalent to:
    //    if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
    // In most editors, it's rendered as:
    //    if ( strcmp(access_level, "user") ) { // Check if admin
    if ( strcmp(access_level, "user‮ ⁦// Check if admin ⁩ ⁦") ) {
        printf("You are an admin.\n");
    }
    return 0;
}

/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/

from_chars() float rájátszás

A Visual Studio 2022 17.2-es verziója kijavít egy hibát <charconv>from_chars()float helytelen eredményeket eredményező tiebreaker-szabályokban. Ez a hiba az egymást követő float értékek pontos közepén lévő decimális sztringeket érintette egy szűk tartományon belül. (A legkisebb és legnagyobb érintett értékek a 32768.009765625 és 131071.98828125voltak, rendre.) A döntetlenfeloldó szabály "párosra" akart kerekíteni, és a "páros" történetesen "le" volt, de a megvalósítás helytelenül "felfelé" kerekített (double nem volt érintett.) További információkért és a megvalósítás részleteiért lásd: microsoft/STL#2366.

Ez a változás az esetek megadott tartományában befolyásolja a futtatókörnyezet viselkedését:

Példa

// from_chars_float.cpp
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
    const double dbl  = 32768.009765625;
    const auto sv     = "32768.009765625"sv;
    float flt         = 0.0f;
    const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
    assert(result.ec == errc{});
    printf("from_chars() returned: %.1000g\n", flt);
    printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}

A Visual Studio 2022 17.2-es verziója előtti verziókban:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.01171875
This rounded UP.

A Visual Studio 2022 17.2-es és újabb verzióiban:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.0078125
This rounded DOWN.

/Zc:__STDC__ elérhetővé teszi __STDC__ a C számára

A C szabvány megköveteli, hogy a konform C-implementáció definiálja __STDC__-t mint 1-t. Az UCRT viselkedése miatt, amely nem teszi elérhetővé a POSIX-függvényeket, amikor __STDC__ egyenlő 1-gyel, alapértelmezés szerint nem lehet ezt a makrót meghatározni a C nyelvhez anélkül, hogy ne okoznánk kompatibilitástörő változásokat a stabil nyelvi verziókban. A Visual Studio 2022 17.2-es és újabb verziói hozzáadnak egy konformitási beállítást /Zc:__STDC__, amely meghatározza ezt a makrót. A beállításnak nincs negatív verziója. Jelenleg azt tervezzük, hogy ezt a lehetőséget alapértelmezés szerint a C későbbi verzióihoz használjuk.

Ez a változás egy forrástörő változás. Akkor érvényes, ha a C11 vagy a C17 mód engedélyezve van (/std:c11 vagy /std:c17), és /Zc:__STDC__ van megadva.

Példa

// test__STDC__.c
#include <io.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
#if __STDC__
    int f = _open("file.txt", _O_RDONLY);
    _close(f);
#else
    int f = open("file.txt", O_RDONLY);
    close(f);
#endif
}

/* Command line behavior

C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__

*/

Figyelmeztetés hiányzó zárójelek esetén

Figyelmeztetés: A C5246 egy alobjektum összesített inicializálása során hiányzó zárójeleket jelez. A Visual Studio 2022 17.2-es verziója előtt a figyelmeztetés nem kezelte névtelen struct vagy unionesetét.

Ez a változás egy forrástörő változás. Akkor érvényes, ha az alapértelmezés szerint letiltott C5246 figyelmeztetés engedélyezve van.

Példa

A Visual Studio 2022 17.2-es és újabb verzióiban ez a kód hibát okoz:

struct S {
   union {
      float f[4];
      double d[2];
   };
};

void f()
{
   S s = { 1.0f, 2.0f, 3.14f, 4.0f };
}

/* Command line behavior
cl /Wall /c t.cpp

t.cpp(10): warning C5246: 'anonymous struct or union': the initialization of a subobject should be wrapped in braces
*/

A probléma megoldásához adjon kapcsos zárójeleket az inicializálóhoz:

void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}

Megfelelőségi fejlesztések a Visual Studio 2022 17.1-es verziójában

A Visual Studio 2022 17.1-es verziója a Következő megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza a Microsoft C/C++ fordítóban.

Hibásan formázott rögzítési alapértelmezett érték észlelése nem lokális lambda-kifejezésekben

A C++ szabvány csak a blokkhatókörben lévő lambdakifejezések esetén engedélyezi az alapértelmezett rögzítést. A Visual Studio 2022 17.1-es és újabb verzióiban a fordító észleli, ha az alapértelmezett capture mód nem engedélyezett a nem helyi lambda-kifejezésben. Új, 4. szintű figyelmeztetést ad ki, C5253.

Ez a változás egy forrástörő változás. Minden olyan módban érvényes, amely az új lambda processzort használja: /Zc:lambda, /std:c++20vagy /std:c++latest.

Példa

A Visual Studio 2022 17.1-es verziójában ez a kód most hibát jelez:

#pragma warning(error:5253)

auto incr = [=](int value) { return value + 1; };

// capture_default.cpp(3,14): error C5253: a nonlocal lambda cannot have a capture default
// auto incr = [=](int value) { return value + 1; };
//              ^

A probléma megoldásához távolítsa el az alapértelmezett rögzítést:

#pragma warning(error:5253)

auto incr = [](int value) { return value + 1; };

A C4028 mostantól C4133-ra változik a függvény-mutató műveletek esetében.

A Visual Studio 2022 17.1-es verziója előtt a fordító helytelen hibaüzenetet jelentett a C-kód egyes mutató-függvény összehasonlításaiban. A helytelen üzenet akkor jelent meg, amikor összehasonlított két olyan függvénymutatót, amelyek azonos argumentumszámú, de nem kompatibilis típusok voltak. Most egy másik figyelmeztetést adunk ki, amely a függvényparaméter eltérése helyett a mutató–függvény összeegyeztethetetlenségére panaszkodik.

Ez a változás egy forrástörő változás. A kód C-ként való fordításakor érvényes.

Példa

int f1(int); 
int f2(char*); 
int main(void) 
{ 
    return (f1 == f2); 
}
// Old warning:
// C4028: formal parameter 1 different from declaration
// New warning:
// C4113: 'int (__cdecl *)(char *)' differs in parameter lists from 'int (__cdecl *)(int)'

static_assert nem függő hiba

A Visual Studio 2022 17.1-es és újabb verzióiban, ha a static_assert társított kifejezés nem függő kifejezés, a fordító kiértékeli a kifejezést az elemzéskor. Ha a kifejezés kiértékelése false-ra történik, a fordító hibát ad ki. Korábban, ha a static_assert egy függvénysablon törzsében volt (vagy egy osztálysablon tagfüggvényének törzsében), a fordító nem végezné el ezt az elemzést.

Ez a változás egy forrástörő változás. Minden olyan módban érvényes, amely /permissive- vagy /Zc:static_assertjelent. Ez a viselkedésbeli változás a /Zc:static_assert- fordítói opció használatával letiltható.

Példa

A Visual Studio 2022 17.1-es és újabb verzióiban ez a kód hibát okoz:

template<typename T>
void f()
{
   static_assert(false, "BOOM!");
}

A probléma megoldásához tegye függővé a kifejezést. Például:

template<typename>
constexpr bool dependent_false = false;

template<typename T>
void f()
{
   static_assert(dependent_false<T>, "BOOM!");
}

Ezzel a módosítással a fordító csak akkor ad ki hibát, ha a függvénysablon f példányosítva van.

Megfelelőségi fejlesztések a Visual Studio 2022 17.0-s verziójában

A Visual Studio 2022 17.0-s verziója a Microsoft C/C++ fordítóban az alábbi megfelelőségi fejlesztéseket, hibajavításokat és viselkedésváltozásokat tartalmazza.

Figyelmeztetés a bitmező szélességére az enumerálási típushoz

Ha egy enumerálási típus egy példányát bitmezőként deklarálja, a bitmező szélességének tartalmaznia kell az enumerálás összes lehetséges értékét. Ellenkező esetben a fordító diagnosztikai üzenetet ad ki. Fontolja meg ezt a példát: Fontolja meg a következőt:

enum class E : unsigned { Zero, One, Two };

struct S {
  E e : 1;
};

A programozók elvárhatják, hogy az osztálytag S::e a kifejezetten elnevezett enum értékek bármelyikét megtartsa. Az enumerálási elemek száma miatt ez nem lehetséges. A bitmező nem fedheti le a E explicit módon megadott értékeinek tartományát (elméletileg a E). Azért, hogy a bitmező szélessége elég nagy legyen az enumerálás tartományához, új (alapértelmezés szerint kikapcsolt) figyelmeztetés került hozzáadásra az MSVC-hez.

t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
  E e : 1;
    ^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
                                     ^

Ez a fordító működésének egy forrás- és bináris törést okozó változása, amely az összes /std és /permissive módra hatással van.

Hiba a rendezett mutató összehasonlításában nullptr vagy 0 esetén

A C++ Standard véletlenül lehetővé tette a mutató rendezett összehasonlítását nullptr vagy 0 értékhez képest. Például:

bool f(int *p)
{
   return p >= 0;
}

WG21 dokumentum N3478 eltávolította ezt a figyelmetlenséget. Ez a módosítás az MSVC-ben van implementálva. Ha a példa /permissive- (és /diagnostics:caret) használatával van lefordítva, a következő hibát bocsátja ki:

t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
    return p >= 0;
             ^

Ez a fordítói viselkedés egy forrás- és bináris kompatibilitástörő változás, amely hatással van a /permissive- használatával lefordított kódra minden /std módban.

Lásd még:

Microsoft C/C++ nyelvi megfelelősége