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 2017-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 fejlesztéseket főverzió, majd verzió szerint sorolja fel. Ha közvetlenül egy adott verzió módosításaira szeretne ugrani, használja a cikkben található alábbi listát.

Ez a dokumentum a Visual Studio 2017 változásait sorolja fel. A Visual Studio 2022 változásairól a Visual Studio 2022 C++ megfelelőségi fejlesztései című témakörben olvashat. A Visual Studio 2019 változásairól a Visual Studio 2019 C++ megfelelőségi fejlesztései című témakörben olvashat. A korábbi megfelelőségi fejlesztések teljes listáját a Visual C++ Újdonságok 2003–2015 című témakörben találja.

Megfelelőségi fejlesztések a Visual Studio 2017 RTW-ben (15.0-s verzió)

Az aggregátumok általános constexpr és nem statikus adattag-inicializálásának (NSDMI) támogatásával a Visual Studio 2017 MSVC-fordítója már a C++14 szabványban hozzáadott funkciókhoz is elérhető. A fordító azonban továbbra sem rendelkezik néhány funkcióval a C++11 és a C++98 szabványból. Tekintse meg a Microsoft C/C++ nyelvének megfelelőségét a fordító aktuális állapotáról.

C++11: Expression SFINAE-támogatás további kódtárakban

A fordító továbbra is javítja az SFINAE kifejezés támogatását. A sablonargumentumok levonásához és helyettesítéséhez szükséges, hogy a decltypeconstexpr kifejezések sablonparaméterekként jelenjenek meg. További információ: Expression SFINAE fejlesztések a Visual Studio 2017 RC-ben.

C++14: NSDMI aggregált típusokhoz

Az összesítés olyan tömb vagy osztály, amely rendelkezik: nincs felhasználó által biztosított konstruktor, nincsenek privát vagy védett nem statikus adattagok, nincsenek alaposztályok és virtuális függvények. A C++14-től kezdődő összesítések tag inicializálókat tartalmazhatnak. További információ: Tagi inicializálók és összesítések.

C++14: Bővített constexpr

A deklarált constexpr kifejezések mostantól tartalmazhatnak bizonyos típusú deklarációkat, ha és válthatnak utasításokat, hurkos utasításokat, valamint olyan objektumok mutációját, amelyek élettartama a constexpr kifejezés kiértékelése során kezdődött. Már nem követelmény, hogy egy constexpr nem statikus tagfüggvénynek implicit módon constkell lennie. További információkért lásd: A constexpr függvények korlátozásának enyhítése.

C++17: Terse static_assert

az üzenet paramétere static_assert nem kötelező. További információ : N3928: Static_assert kiterjesztése, v2.

C++17: [[fallthrough]] attribútum

A /std:c++17 és újabb módokban az [[fallthrough]] attribútum a kapcsoló utasítások kontextusában használható a fordító számára, hogy jelezze, hogy az átesési viselkedés szándékos. Ez az attribútum megakadályozza, hogy a fordító figyelmeztetéseket adjon ki ilyen esetekben. További információért lásd P0188R0 - Wording for [[fallthrough]] attribute.

Általánosított tartományalapú for hurkok

A tartományalapú for hurkokhoz már nincs szükség erre, begin() és end() ugyanolyan típusú objektumokat ad vissza. Ez a módosítás lehetővé teszi, hogy a end() egy sentinelt adjon vissza a range-v3-ban használt tartományok és a befejezett, de még nem teljesen közzétett Ranges műszaki specifikáció szerint. További információért lásd P0184R0 - Generalizing the Range-Based for Loop.

Másolási lista inicializálása

A Visual Studio 2017 helyesen jelzi az objektumlétrehozással kapcsolatos fordítóhibákat, ha inicializáló listákat használnak. Ezeket a hibákat a Visual Studio 2015 nem észlelte, és összeomlásokhoz vagy nem definiált futtatókörnyezeti viselkedéshez vezethet. Ennek megfelelően N4594 13.3.1.7p1copy-list-initialization a fordítónak explicit konstruktort kell figyelembe vennie a túlterhelés feloldásához. Ennek azonban hibát kell okoznia, ha ezt a túlterhelést választják ki.

Az alábbi két példa a Visual Studio 2015-ben készül, de a Visual Studio 2017-ben nem.

struct A
{
    explicit A(int) {}
    A(double) {}
};

int main()
{
    A a1 = { 1 }; // error C3445: copy-list-initialization of 'A' cannot use an explicit constructor
    const A& a2 = { 1 }; // error C2440: 'initializing': cannot convert from 'int' to 'const A &'

}

A hiba kijavításához használja a közvetlen inicializálást:

A a1{ 1 };
const A& a2{ 1 };

A Visual Studio 2015-ben a fordító hibásan kezelte a másolt lista inicializálást ugyanúgy, mint a hagyományos másolási inicializálást: csak az átalakító konstruktorokat vette figyelembe a túlterhelés feloldásához. Az alábbi példában a Visual Studio 2015 a MyInt(23)-t választja. A Visual Studio 2017 helyesen emeli ki a hibát.

// From https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1228
struct MyStore {
    explicit MyStore(int initialCapacity);
};

struct MyInt {
    MyInt(int i);
};

struct Printer {
    void operator()(MyStore const& s);
    void operator()(MyInt const& i);
};

void f() {
    Printer p;
    p({ 23 }); // C3066: there are multiple ways that an object
        // of this type can be called with these arguments
}

Ez a példa hasonló az előzőhöz, de egy másik hibát jelez. A Visual Studio 2015-ben sikeres, és a Visual Studio 2017-ben a C2668-tal meghiúsul.

struct A {
    explicit A(int) {}
};

struct B {
    B(int) {}
};

void f(const A&) {}
void f(const B&) {}

int main()
{
    f({ 1 }); // error C2668: 'f': ambiguous call to overloaded function
}

Elavult típusdefinitek

A Visual Studio 2017 most kiadja a megfelelő figyelmeztetést az osztályban vagy szerkezetben deklarált elavult típusdefekre. Az alábbi példa figyelmeztetések nélkül fordít le a Visual Studio 2015-ben. C4996-ot állít elő a Visual Studio 2017-ben.

struct A
{
    // also for __declspec(deprecated)
    [[deprecated]] typedef int inttype;
};

int main()
{
    A::inttype a = 0; // C4996 'A::inttype': was declared deprecated
}

constexpr

A Visual Studio 2017 helyesen jelez hibát, ha egy feltételes kiértékelési művelet bal oldali operandusa nem érvényes egy constexpr környezetben. Az alábbi kód lefordul a Visual Studio 2015-ben, de nem a Visual Studio 2017-ben, ahol a C3615 hibát adja:

template<int N>
struct array
{
    int size() const { return N; }
};

constexpr bool f(const array<1> &arr)
{
    return arr.size() == 10 || arr.size() == 11; // C3615 constexpr function 'f' cannot result in a constant expression
}

A hiba kijavításához vagy deklarálja a array::size() függvényt constexpr-ként, vagy távolítsa el a constexpr minősítőt a f-ból.

Variadikus függvények számára átadott osztálytípusok

A Visual Studio 2017-ben a variadikus függvénynek átadott osztályoknak vagy szerkezeteknek, például printf triviálisan másolhatónak kell lenniük. Az ilyen objektumok átadásakor a fordító egyszerűen egy bitenkénti másolatot készít, és nem hívja meg a konstruktort vagy a destruktort.

#include <atomic>
#include <memory>
#include <stdio.h>

int main()
{
    std::atomic<int> i(0);
    printf("%i\n", i); // error C4839: non-standard use of class 'std::atomic<int>'
                        // as an argument to a variadic function.
                        // note: the constructor and destructor will not be called;
                        // a bitwise copy of the class will be passed as the argument
                        // error C2280: 'std::atomic<int>::atomic(const std::atomic<int> &)':
                        // attempting to reference a deleted function

    struct S {
        S(int i) : i(i) {}
        S(const S& other) : i(other.i) {}
        operator int() { return i; }
    private:
        int i;
    } s(0);
    printf("%i\n", s); // warning C4840 : non-portable use of class 'main::S'
                      // as an argument to a variadic function
}

A hiba kijavításához meghívhat egy tagfüggvényt, amely egy triviálisan másolható típust ad vissza.

    std::atomic<int> i(0);
    printf("%i\n", i.load());

vagy használjon statikus kasztot az objektum konvertálásához, mielőtt átadja:

    struct S {/* as before */} s(0);
    printf("%i\n", static_cast<int>(s))

A használatával CStringlétrehozott és felügyelt sztringek esetében a megadott operator LPCTSTR() értéket kell használni egy objektumnak a formátumsztring által várt C mutatóra való vetéséhez CString .

CString str1;
CString str2 = _T("hello!");
str1.Format(_T("%s"), static_cast<LPCTSTR>(str2));

Cv-minősítők az osztály létrehozása során

A Visual Studio 2015-ben a fordító néha helytelenül figyelmen kívül hagyja a cv-minősítőt, amikor egy osztályobjektumot konstruktorhíváson keresztül hoz létre. Ez a probléma összeomlást vagy váratlan futtatókörnyezeti viselkedést okozhat. Az alábbi példa a Visual Studio 2015-ben fordít, de fordítói hibát jelez a Visual Studio 2017-ben:

struct S
{
    S(int);
    operator int();
};

int i = (const S)0; // error C2440

A hiba kijavításához deklarálja operator int() a következőt const: .

Hozzáférés-ellenőrzés a minősített neveken a sablonokban

A fordító korábbi verziói bizonyos sablonkörnyezetekben nem ellenőrizták a minősített nevekhez való hozzáférést. Ez a probléma megzavarhatja az SFINAE várt viselkedését, ahol a helyettesítés a név elérhetetlensége miatt várhatóan meghiúsul. Futásidőben összeomlást vagy váratlan viselkedést okozhatott, mert a fordító helytelenül nevezte az operátor helytelen túlterhelését. A Visual Studio 2017-ben fordítóhiba lépett fel. Az adott hiba eltérő lehet, de jellemző hiba a C2672, "nem található egyező túlterhelt függvény". A következő kód fordítása a Visual Studio 2015-ben történik, de hibát jelez a Visual Studio 2017-ben:

#include <type_traits>

template <class T> class S {
    typedef typename T type;
};

template <class T, std::enable_if<std::is_integral<typename S<T>::type>::value, T> * = 0>
bool f(T x);

int main()
{
    f(10); // C2672: No matching overloaded function found.
}

Hiányzó sablonargumentumlisták

A Visual Studio 2015-ben és korábbi verzióiban a fordító nem diagnosztizálta az összes hiányzó sablonargumentumlistát. Nem jegyezné meg, hogy a hiányzó sablon mikor jelent meg egy sablonparaméter-listában: például amikor egy alapértelmezett sablonargumentum vagy egy nem típus típusú sablonparaméter egy része hiányzott. Ez a probléma előre nem látható működést eredményezhet, beleértve a fordító összeomlását vagy a futtatókörnyezet váratlan viselkedését. Az alábbi kód fordítása a Visual Studio 2015-ben történik, de hibát okoz a Visual Studio 2017-ben.

template <class T> class ListNode;
template <class T> using ListNodeMember = ListNode<T> T::*;
template <class T, ListNodeMember M> class ListHead; // C2955: 'ListNodeMember': use of alias
                                                     // template requires template argument list

// correct:  template <class T, ListNodeMember<T> M> class ListHead;

Expression-SFINAE

A kifejezés-SFINAE támogatásához a fordító most már a decltype argumentumokat elemzi, amikor a sablonokat deklarálják, nem pedig példányosítják. Tehát ha nem függő specializáció található az decltype argumentumban, azt nem halasztják el a példányosítási időpontig. A folyamat azonnal feldolgozva van, és az esetlegesen felmerülő hibákat a rendszer akkor diagnosztizálja.

Az alábbi példa egy ilyen fordítóhibát mutat be, amely a deklaráláskor merül fel:

#include <utility>
template <class T, class ReturnT, class... ArgsT>
class IsCallable
{
public:
    struct BadType {};

    template <class U>
    static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U>

    template <class U>
    static BadType Test(...);

    static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value;
};

constexpr bool test1 = IsCallable<int(), int>::value;
static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");

Névtelen névterekben deklarált osztályok

A C++ szabvány szerint egy névtelen névtérben deklarált osztály belső kapcsolatokkal rendelkezik, ami azt jelenti, hogy nem exportálható. A Visual Studio 2015-ben és korábbi verzióiban ez a szabály nem lett kényszerítve. A Visual Studio 2017-ben a szabály részlegesen érvényes. A Visual Studio 2017-ben az alábbi példa c2201-et jelez:

struct __declspec(dllexport) S1 { virtual void f() {} };
  // C2201 const anonymous namespace::S1::vftable: must have external linkage
  // in order to be exported/imported.

Az értékosztálytagok alapértelmezett inicializálói (C++/CLI)

A Visual Studio 2015-ben és korábbi verzióiban a fordító engedélyezte (de figyelmen kívül hagyta) az alapértelmezett tag inicializálóját egy értékosztály egy tagjának. Az értéktípus alapértelmezett inicializálása mindig nullára inicializálja a tagokat. Az alapértelmezett konstruktor nem engedélyezett. A Visual Studio 2017-ben az alapértelmezett tag-inicializálók fordítóhibát okoznak, ahogyan az ebben a példában látható:

value struct V
{
    int i = 0; // error C3446: 'V::i': a default member initializer
               // isn't allowed for a member of a value class
};

Alapértelmezett indexelők (C++/CLI)

A Visual Studio 2015-ben és korábbi verzióiban a fordító bizonyos esetekben helytelenül állított be alapértelmezett tulajdonságot alapértelmezett indexelőként. A probléma megkerülése az azonosító default használatával lehetséges volt a tulajdonság eléréséhez. Maga a megkerülési megoldás problémássá vált, miután default-t bevezették kulcsszóként a C++11-ben. A Visual Studio 2017-ben kijavították azokat a hibákat, amelyek kerülő megoldást igényeltek. A fordító ekkor hibát jelez, amikor default egy osztály alapértelmezett tulajdonságának eléréséhez használják.

//class1.cs

using System.Reflection;
using System.Runtime.InteropServices;

namespace ClassLibrary1
{
    [DefaultMember("Value")]
    public class Class1
    {
        public int Value
        {
            // using attribute on the return type triggers the compiler bug
            [return: MarshalAs(UnmanagedType.I4)]
            get;
        }
    }
    [DefaultMember("Value")]
    public class Class2
    {
        public int Value
        {
            get;
        }
    }
}

// code.cpp
#using "class1.dll"

void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2)
{
       r1->Value; // error
       r1->default;
       r2->Value;
       r2->default; // error
}

A Visual Studio 2017-ben mindkét értéktulajdonság a nevük alapján érhető el:

#using "class1.dll"

void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2)
{
       r1->Value;
       r2->Value;
}

Megfelelőségi fejlesztések a 15.3-ban

constexpr lambdas

A Lambda-kifejezések mostantól állandó kifejezésekben is használhatók. További információ: constexpr lambdakifejezések a C++-ban.

if constexpr függvénysablonokban

Egy függvénysablon tartalmazhat if constexpr utasításokat a fordítási idő alatti elágazás engedélyezésére. További információ: if constexpr utasítások.

Kijelölési utasítások inicializálókkal

Az if utasítások tartalmazhatnak inicializálót, amely egy változót vezet be a blokk hatókörében magában az utasításban. További információkért lásd if az inicializálóval kapcsolatos utasításokat.

[[maybe_unused]] és [[nodiscard]] attribútumok

Az új attribútum [[maybe_unused]] elnémítja a figyelmeztetéseket, ha egy entitás nincs használatban. Az [[nodiscard]] attribútum figyelmeztetést hoz létre, ha egy függvényhívás visszatérési értéke el van vetve. További információ: Attribútumok a C++-ban.

Attribútumnévterek használata ismétlés nélkül

Új szintaxis, amely csak egyetlen névtér-azonosítót engedélyez egy attribútumlistában. További információ: Attribútumok a C++-ban.

Strukturált kötések

Mostantól egyetlen deklarációban tárolhat olyan értéket, amelynek összetevői egyedi névvel rendelkeznek, ha az érték egy tömb, egy std::tuple, egy std::pair vagy az összes nyilvános, nem statikus adattaggal rendelkezik. További információ: P0144R0 - Structured Bindingstöbb érték visszaadása egy függvényből.

Értékekre vonatkozó építési szabályok enum class

Most már implicit konverzió van a nem szűkített hatókörű enumerációkhoz. A hatókörrel rendelkező enumerálás mögöttes típusából magát az enumerálást alakítja át. Az átalakítás akkor érhető el, ha definíciója nem vezet be számbavételt, és ha a forrás lista inicializálási szintaxist használ. További információkért tekintse meg P0138R2 - Construction Rules for enum class Values és az Enumerációk részt.

Rögzítés *this érték szerint

A *this lambda kifejezésben szereplő objektumot mostantól érték rögzíti. Ez a módosítás olyan forgatókönyveket tesz lehetővé, amelyekben a lambda meghívása párhuzamos és aszinkron műveletekben történik, különösen az újabb géparchitektúrák esetében. További információért lásd P0018R3 - Lambda Capture of *this by Value as [=,*this].

operator++ eltávolítása bool javára

operator++ a továbbiakban nem támogatott a típusok esetében bool . További információért lásd P0002R1 - Remove Deprecated operator++(bool).

Elavult register kulcsszó eltávolítása

A register korábban elavult (és a fordító által figyelmen kívül hagyott) kulcsszót a program eltávolítja a nyelvről. További információért lásd P0001R1 - Remove Deprecated Use of the register Keyword.

Törölt tagsablonok meghívása

A Visual Studio korábbi verzióiban a fordító bizonyos esetekben nem bocsát ki hibát a törölt tagsablonok hibásan formázott hívásai esetén. Ezek a hívások futásidőben összeomlást okozhatnak. A következő kód mostantól C2280-at hoz létre:

template<typename T>
struct S {
   template<typename U> static int f() = delete;
};

void g()
{
   decltype(S<int>::f<int>()) i; // this should fail with
// C2280: 'int S<int>::f<int>(void)': attempting to reference a deleted function
}

A hiba kijavításához deklarálja i a következőt int: .

Típustulajdonságok előfeltétel-ellenőrzése

A Visual Studio 2017 15.3-s verziója javítja a típustulajdonságok előfeltétel-ellenőrzését, hogy szigorúbban kövesse a szabványt. Az egyik ilyen ellenőrzés az, hogy hozzárendelhető-e. A következő kód állítja elő a C2139-et a Visual Studio 2017 15.3-os verziójában:

struct S;
enum E;

static_assert(!__is_assignable(S, S), "fail"); // C2139 in 15.3
static_assert(__is_convertible_to(E, E), "fail"); // C2139 in 15.3

Új fordítói figyelmeztetések és futásidejű ellenőrzések a natív és a kezelt kód közötti összekapcsolás során

A felügyelt függvényekből natív függvényekbe való híváshoz marsallálás szükséges. A CLR elvégzi az adatkezelést, de nem érti a C++ szemantikáját. Ha natív objektumot ad át érték szerint, a CLR vagy meghívja az objektum másolás-konstruktorát, vagy használja BitBltazt, ami futásidőben meghatározatlan viselkedést okozhat.

Most a fordító figyelmeztetést ad ki, ha ezt a hibát a fordításkor találja: a törölt másolási ctorral rendelkező natív objektumot egy natív és egy felügyelt határ között érték szerint adja át a rendszer. Azokban az esetekben, amikor a fordító nem tud a fordításkor, futásidejű ellenőrzést injektál, hogy a program azonnal hívjon std::terminate , ha rosszul formázott marshaling történik. A Visual Studio 2017 15.3-s verziójában a következő kód a C4606 figyelmeztetést eredményezi:

class A
{
public:
   A() : p_(new int) {}
   ~A() { delete p_; }

   A(A const &) = delete;
   A(A &&rhs) {
   p_ = rhs.p_;
}

private:
   int *p_;
};

#pragma unmanaged

void f(A a)
{
}

#pragma managed

int main()
{
    // This call from managed to native requires marshaling. The CLR doesn't
    // understand C++ and uses BitBlt, which results in a double-free later.
    f(A()); // C4606 'A': passing argument by value across native and managed
    // boundary requires valid copy constructor. Otherwise, the runtime
    // behavior is undefined.
}

A hiba kijavításához távolítsa el az #pragma managed irányelvet, hogy natívként jelölje meg a hívót, és elkerülje a marsallást.

Kísérleti API-figyelmeztetés WinRT-hez

A kísérletezéshez és visszajelzéshez kiadott WinRT API-kat a rendszer megjelöli Windows.Foundation.Metadata.ExperimentalAttribute. A Visual Studio 2017 15.3-s verziójában a fordító c4698 figyelmeztetést állít elő ehhez az attribútumhoz. A Windows SDK korábbi verzióiban néhány API már ki van díszítve az attribútummal, és az ezekhez az API-khoz intézett hívások most aktiválják ezt a fordítói figyelmeztetést. Az újabb Windows SDK-k minden szállított típusból eltávolítják az attribútumot. Ha régebbi SDK-t használ, el kell tiltania ezeket a figyelmeztetéseket a kiszállított típusok összes hívására vonatkozóan.

A következő kód a C4698 figyelmeztetést állítja elő:

Windows::Storage::IApplicationDataStatics2::GetForUserAsync(); // C4698
// 'Windows::Storage::IApplicationDataStatics2::GetForUserAsync' is for
// evaluation purposes only and is subject to change or removal in future updates

A figyelmeztetés letiltásához adjon hozzá egy #pragma:

#pragma warning(push)
#pragma warning(disable:4698)

Windows::Storage::IApplicationDataStatics2::GetForUserAsync();

#pragma warning(pop)

Sablontagfüggvény soron kívüli definíciója

A Visual Studio 2017 15.3-as verziója hibát okoz az osztályban nem deklarált sablontagfüggvény soron kívüli definíciója esetén. A következő kód most c2039-et eredményez:

struct S {};

template <typename T>
void S::f(T t) {} // C2039: 'f': is not a member of 'S'

A hiba kijavításához adjon hozzá egy deklarációt az osztályhoz:

struct S {
    template <typename T>
    void f(T t);
};
template <typename T>
void S::f(T t) {}

A this mutató címének megszerzése iránti kísérlet

C++-ban a this egy X típusú mutató prvalue-ja. Nem veheted a this címét, és nem kötheted egy lvalue-referenciához. A Visual Studio korábbi verzióiban a fordítóprogram lehetővé tette a korlátozás megkerülését egy típuskonverzió használatával. A Visual Studio 2017 15.3-s verziójában a fordító C2664-es hibát eredményez.

Átalakítás elérhetetlen alaposztályra

A Visual Studio 2017 15.3-s verziója hibát okoz, ha egy típust elérhetetlen alaposztálysá próbál konvertálni. Az alábbi kód nem formázott, és futásidőben összeomlást okozhat. A fordító ekkor létrehozza a C2243-at , amikor az így látja a kódot:

#include <memory>

class B { };
class D : B { }; // C2243: 'type cast': conversion from 'D *' to 'B *' exists, but is inaccessible

void f()
{
   std::unique_ptr<B>(new D());
}

Az alapértelmezett argumentumok nem engedélyezettek a tagfüggvények soron kívüli definícióiban

Az alapértelmezett argumentumok nem engedélyezettek a sablonosztályok tagfüggvényeinek soron kívüli definícióiban. A fordító figyelmeztetést ad ki a(z) /permissive alatt, és súlyos hibát a(z) /permissive- alatt.

A Visual Studio korábbi verzióiban a következő rosszul formázott kód futásidejű összeomlást okozhat. A Visual Studio 2017 15.3-s verziója c5037 figyelmeztetést jelenít meg:

template <typename T>
struct A {
    T f(T t, bool b = false);
};

template <typename T>
T A<T>::f(T t, bool b = false) // C5037: 'A<T>::f': an out-of-line definition of a member of a class template cannot have default arguments
{
    // ...
}

A hiba kijavításához távolítsa el az = false alapértelmezett argumentumot.

offsetof Az összetett tagtervező használata

A Visual Studio 2017 15.3-as verziójában az offsetof(T, m) használata, ahol m egy "összetett tagkijelölő", figyelmeztetést eredményez a fordításkor a /Wall opció használatával. Az alábbi kód helytelenül formázott, és futásidőben összeomlást okozhat. A Visual Studio 2017 15.3-ás verziója figyelmeztetést készít a C4841-ről:

struct A {
   int arr[10];
};

// warning C4841: non-standard extension used: compound member designator used in offsetof
constexpr auto off = offsetof(A, arr[2]);

A kód javításához tiltsa le a figyelmeztetést egy pragmával, vagy módosítsa a kódot úgy, hogy ne használja offsetof:

#pragma warning(push)
#pragma warning(disable: 4841)
constexpr auto off = offsetof(A, arr[2]);
#pragma warning(pop)

Statikus adattag vagy tagfüggvény használata offsetof

A Visual Studio 2017 15.3-ás verziójában az offsetof(T, m)m statikus adattagra vagy tagfüggvényre hivatkozva hibát eredményez. A következő kód c4597-et eredményez:

#include <cstddef>

struct A {
   int ten() { return 10; }
   static constexpr int two = 2;
};

constexpr auto off = offsetof(A, ten);  // C4597: undefined behavior: offsetof applied to member function 'A::ten'
constexpr auto off2 = offsetof(A, two); // C4597: undefined behavior: offsetof applied to static data member 'A::two'

Ez a kód nem formázott, és futásidőben összeomlást okozhat. A hiba kijavításához módosítsa úgy a kódot, hogy többé ne hívja meg a nem definiált viselkedést. Ez nem hordozható kód, amelyet a C++ szabvány nem engedélyez.

Új figyelmeztetés attribútumokra __declspec

A Visual Studio 2017 15.3-as verziójában a fordító többé nem hagyja figyelmen kívül az attribútumokat, ha a __declspec(...) attribútumot a extern "C" csatolási specifikáció előtt alkalmazzák. Korábban a fordító figyelmen kívül hagyta az attribútumot, ami futásidejű következményekkel járhat. Ha a /Wall és /WX opciók be vannak állítva, a következő kód a C4768 figyelmeztetést eredményezi:

__declspec(noinline) extern "C" HRESULT __stdcall // C4768: __declspec attributes before linkage specification are ignored

A figyelmeztetés kijavításához először tegye a következőt extern "C" :

extern "C" __declspec(noinline) HRESULT __stdcall

Ez a figyelmeztetés alapértelmezés szerint ki van kapcsolva a Visual Studio 2017 15.3-s verziójában, és csak a következővel /Wall/WXlefordított kódot érinti. A Visual Studio 2017 15.5-ös verziójától kezdve alapértelmezés szerint 3. szintű figyelmeztetésként van engedélyezve.

decltype és a törölt destruktorokra irányuló hívások

A Visual Studio korábbi verzióiban a fordító nem észlelte, hogy egy törölt destruktor hívása történt-e a társított decltypekifejezés kontextusában. A Visual Studio 2017 15.3-s verziójában a következő kód c2280-at eredményez:

template<typename T>
struct A
{
   ~A() = delete;
};

template<typename T>
auto f() -> A<T>;

template<typename T>
auto g(T) -> decltype((f<T>()));

void h()
{
   g(42); // C2280: 'A<T>::~A(void)': attempting to reference a deleted function
}

Nem inicializált konstansváltozók

A Visual Studio 2017 RTW kiadásának volt egy regressziója: a C++ fordító nem adott ki diagnosztikát egy nem inicializált const változóhoz. Ezt a regressziót kijavítottuk a Visual Studio 2017 15.3-s verziójában. A következő kód mostantól C4132 figyelmeztetést eredményez:

const int Value; // C4132: 'Value': const object should be initialized

A hiba kijavításához rendeljen hozzá egy értéket Value.

Üres deklarációk

A Visual Studio 2017 15.3-as verziója mostantól nem csak a beépített típusok üres deklarációira figyelmeztet. Az alábbi kód mostantól a 2. szintű C4091 figyelmeztetést állítja elő mind a négy deklarációhoz:

struct A {};
template <typename> struct B {};
enum C { c1, c2, c3 };

int;    // warning C4091 : '' : ignored on left of 'int' when no variable is declared
A;      // warning C4091 : '' : ignored on left of 'main::A' when no variable is declared
B<int>; // warning C4091 : '' : ignored on left of 'B<int>' when no variable is declared
C;      // warning C4091 : '' : ignored on left of 'C' when no variable is declared

A figyelmeztetések eltávolításához megjegyzést fűzhet hozzá, vagy eltávolíthatja az üres deklarációkat. Azokban az esetekben, amikor a névtelen objektumnak mellékhatása van (például RAII), nevet kell adni neki.

A figyelmeztetés ki van zárva /Wv:18 alatt, és alapértelmezés szerint be van kapcsolva a W2 figyelmeztetési szinten.

std::is_convertible tömbtípusokhoz

A fordító korábbi verziói helytelen eredményeket adtak a tömbtípusokhoz std::is_convertible . Ehhez a könyvtáríróknak speciális esetként kellett kezelniük a Microsoft C++ fordítót a std::is_convertible<...> típustulajdonság használatakor. Az alábbi példában a statikus állítások a Visual Studio korábbi verzióiban lépnek érvénybe, de a Visual Studio 2017 15.3-as verziójában meghiúsulnak:

#include <type_traits>

using Array = char[1];

static_assert(std::is_convertible<Array, Array>::value);
static_assert(std::is_convertible<const Array, const Array>::value, "");
static_assert(std::is_convertible<Array&, Array>::value, "");
static_assert(std::is_convertible<Array, Array&>::value, "");

std::is_convertible<From, To> a rendszer úgy számítja ki, hogy ellenőrizze, hogy egy képzeletbeli függvénydefiníció megfelelően van-e kialakítva:

   To test() { return std::declval<From>(); }

Privát destruktorok és std::is_constructible

A fordító korábbi verziói figyelmen kívül hagyták a destruktor privát voltát az eredmény std::is_constructible meghatározásakor. Most már figyelembe veszi őket. Az alábbi példában a statikus állítások a Visual Studio korábbi verzióiban lépnek érvénybe, de a Visual Studio 2017 15.3-as verziójában meghiúsulnak:

#include <type_traits>

class PrivateDtor {
   PrivateDtor(int) { }
private:
   ~PrivateDtor() { }
};

// This assertion used to succeed. It now correctly fails.
static_assert(std::is_constructible<PrivateDtor, int>::value);

A privát destruktorok miatt egy típus nem konstruálható. std::is_constructible<T, Args...> úgy van kiszámítva, mintha a következő deklaráció lett volna megírva:

   T obj(std::declval<Args>()...)

Ez a hívás destruktorhívást jelent.

C2668: Nem egyértelmű túlterhelés feloldása

A fordító korábbi verziói néha nem észlelték a kétértelműséget, amikor több jelöltet is talált deklarációk és argumentumfüggő keresések használatával. Ez a hiba helytelen túlterheléshez és váratlan futtatókörnyezeti viselkedéshez vezethet. Az alábbi példában a Visual Studio 2017 15.3-s verziója helyesen emeli ki a C2668-at:

namespace N {
   template<class T>
   void f(T&, T&);

   template<class T>
   void f();
}

template<class T>
void f(T&, T&);

struct S {};
void f()
{
   using N::f;

   S s1, s2;
   f(s1, s2); // C2668: 'f': ambiguous call to overloaded function
}

A kód javításához távolítsa el a using N::f utasítást, ha meg szeretné hívni a ::f().

C2660: helyi függvénydeklarációk és argumentumfüggő keresés

A helyi függvénydeklarációk elrejtik a függvénydeklarációt a beágyazási hatókörben, és letiltják az argumentumfüggő kereséseket. A fordító korábbi verziói ebben az esetben mindig argumentumfüggő kereséseket végeztek. Ez váratlan futtatókörnyezeti működéshez vezethet, ha a fordító rossz túlterhelést választott. A hiba oka általában a helyi függvény deklarációjának helytelen aláírása. Az alábbi példában a Visual Studio 2017 15.3-s verziója helyesen emeli ki a C2660-at:

struct S {};
void f(S, int);

void g()
{
   void f(S); // C2660 'f': function does not take 2 arguments:
   // or void f(S, int);
   S s;
   f(s, 0);
}

A probléma megoldásához módosítsa vagy távolítsa el az aláírást f(S) .

C5038: inicializálás sorrendje az inicializáló listákban

Az osztálytagok inicializálva lesznek a deklarált sorrendben, nem pedig az inicializáló listákban megjelenő sorrendben. A fordító korábbi verziói nem figyelmeztettek, amikor az inicializálólista sorrendje eltért a deklaráció sorrendjétől. Ez a probléma nem definiált futtatókörnyezeti viselkedéshez vezethet, ha az egyik tag inicializálása az inicializálás alatt álló lista egy másik tagjától függ. Az alábbi példában a Visual Studio 2017 15.3-as verziója (/Wall-el) figyelmeztetést ad a C5038-at:

struct A
{    // Initialized in reverse, y reused
    A(int a) : y(a), x(y) {} // C5038: data member 'A::y' will be initialized after data member 'A::x'
    int x;
    int y;
};

A probléma megoldásához gondoskodjon az inicializálók listájáról, hogy a deklarációkkal megegyező sorrendben legyen. Hasonló figyelmeztetés akkor fordul elő, ha egy vagy mindkét inicializáló az alaposztály tagjaira hivatkozik.

Ez a figyelmeztetés alapértelmezés szerint ki van kapcsolva, és csak a vele /Walllefordított kódot érinti.

A követelményekhez való igazítás fejlesztése a 15.5-ben

A(z) [14] jelöléssel ellátott funkciók feltétel nélkül elérhetők még módban is /std:c++14 .

Új fordítókapcsoló a extern constexpr számára

A Visual Studio korábbi verzióiban a fordító mindig adott egy constexpr változó belső kapcsolatát, még akkor is, ha a változót megjelölték extern. A Visual Studio 2017 15.5-ös verziójában egy új fordítókapcsoló teszi lehetővé a /Zc:externConstexprhelyes és szabványoknak megfelelő működést. További információ: extern constexpr linkage.

Dinamikus kivétel specifikációinak eltávolítása

P0003R5 A dinamikus kivétel specifikációi elavultak a C++11-ben. A funkció eltávolításra került a C++17-ből, de a (még) elavult throw() specifikáció szigorúan megmarad noexcept(true) aliasaként. További információ: Dinamikus kivétel specifikációjának eltávolítása és noexcept.

not_fn()

P0005R4not_fn egy helyettesítése not1 és not2.

Újrafogalmazás enable_shared_from_this

enable_shared_from_this P0033R1 C++11-ben lett hozzáadva. A C++17 szabvány frissíti a specifikációt bizonyos sarokesetek jobb kezelése érdekében. [14]

Térképek és készletek összekapcsolása

P0083R3 Ez a funkció lehetővé teszi a csomópontok kivonását az asszociatív tárolókból (azaz map, set, unordered_map), unordered_setamelyek ezután módosíthatók és visszaszúrhatók ugyanabba a tárolóba vagy egy másik, azonos csomóponttípust használó tárolóba. (Gyakori használati eset egy csomópont kinyerése egy std::mapadott csomópontból, a kulcs módosítása és újbóli létrehozása.)

A könyvtár maradvány részeinek elavultatása

P0174R2 A C++ standard kódtár számos funkcióját felváltották az évek során újabb funkciók, máskülönben nem bizonyultak hasznosnak vagy problémásnak. Ezek a funkciók hivatalosan elavultak a C++17-ben.

Az allokátor támogatásának eltávolítása a std::function-ból/-ből

P0302R1 A C++17 előtt az osztálysablonnak std::function több konstruktora is volt, amelyek egy kiosztó argumentumot vettek igénybe. A kiosztók használata azonban ebben a kontextusban problémás volt, és a szemantikák nem voltak egyértelműek. A problémás konstruktorokat eltávolították.

Javítások a következőhöz: not_fn()

P0358R1 Az új szövegezés std::not_fn támogatja az értékkategória propagálását, ha burkoló funkció hívásakor használják.

shared_ptr<T[]>, shared_ptr<T[N]>

P0414R2 A változások egyesítése shared_ptr a könyvtár alapjaiból a C++17-be. [14]

Tömbök hibáinak javítása shared_ptr

P0497R0 A tömbök támogatásának shared_ptr javítása. [14]

Tisztázás insert_return_type

P0508R0 Az egyedi kulcsokkal rendelkező asszociatív tárolók és az egyedi kulcsokkal rendelkező rendezetlen tárolók tagfüggvényekkel insert rendelkeznek, amelyek beágyazott típust insert_return_typeadnak vissza. Ez a visszatérési típus most már a tároló Iterátorán és NodeType-ján paraméterezett típus specializációjaként van definiálva.

Beágyazott változók a standard könyvtárban

A P0607R0 esetében a standard kódtárban deklarált számos gyakori változó mostantól beágyazottként van deklarálva.

A D. melléklet funkciói elavultak

A C++ szabvány D. melléklete tartalmazza az elavult összes funkciót, beleértve shared_ptr::unique()a , <codecvt>és namespace std::tr1. Ha be van állítva a /std:c++17 vagy egy későbbi fordítóopció, a D mellékletben található szabványos könyvtárfunkciók szinte mind elavultaként vannak megjelölve. További információ: A D. melléklet standard könyvtárfunkciói elavultként vannak megjelölve.

A std::tr2::sys névtér a <experimental/filesystem> alatt mostantól alapértelmezés szerint elavulásra figyelmeztet, és alapértelmezés szerint el lesz távolítva a /std:c++17 és az utána következő verziókban.

Továbbfejlesztett megfelelőség a <iostream> nem szabványos bővítmények (osztályon belüli explicit specializációk) elkerülésével.

A standard kódtár mostantól belsőleg használ változósablonokat.

A standard kódtár a C++17 fordító módosításainak megfelelően frissült. A frissítések közé tartozik a noexcept hozzáadása a típusrendszerhez, valamint a dinamikus kivételmegadás eltávolítása.

Részleges rendezés módosítása

A fordító most már helyesen elutasítja a következő kódot, és a megfelelő hibaüzenetet adja:

template<typename... T>
int f(T* ...)
{
    return 1;
}

template<typename T>
int f(const T&)
{
    return 2;
}

int main()
{
    int i = 0;
    f(&i);    // C2668
}
t161.cpp
t161.cpp(16): error C2668: 'f': ambiguous call to overloaded function
t161.cpp(8): note: could be 'int f<int*>(const T &)'
        with
        [
            T=int*
        ]
t161.cpp(2): note: or       'int f<int>(int*)'
t161.cpp(16): note: while trying to match the argument list '(int*)'

A fenti példában az a probléma, hogy két különbség van a típusok között (const vs. non-const és pack vs. non-pack). A fordítóhiba kiküszöböléséhez távolítsa el az egyik különbséget. Ezután a fordító egyértelműen rendezheti a függvényeket.

template<typename... T>
int f(T* ...)
{
    return 1;
}

template<typename T>
int f(T&)
{
    return 2;
}

int main()
{
    int i = 0;
    f(&i);
}

Kivételkezelők

A tömbre vagy függvénytípusra mutató hivatkozáskezelők soha nem egyeznek a kivételobjektumok között. A fordító most már helyesen betartja ezt a szabályt, és 4. szintű figyelmeztetést ad a C4843-nak. Használat esetén char* már nem egyezik a sztringkonstans kezelője wchar_t*/Zc:strictStrings vagy a sztringkonstanssal.

int main()
{
    try {
        throw "";
    }
    catch (int (&)[1]) {} // C4843 (This should always be dead code.)
    catch (void (&)()) {} // C4843 (This should always be dead code.)
    catch (char*) {} // This should not be a match under /Zc:strictStrings
}
warning C4843: 'int (&)[1]': An exception handler of reference to array or function type is unreachable, use 'int*' instead
warning C4843: 'void (__cdecl &)(void)': An exception handler of reference to array or function type is unreachable, use 'void (__cdecl*)(void)' instead

A következő kód elkerüli a hibát:

catch (int (*)[1]) {}

std::tr1 a névtér elavult

A nem szabványos std::tr1 névtér mostantól elavultként van megjelölve a C++14 és a C++17 módban is. A Visual Studio 2017 15.5-ös verziójában a következő kód a C4996-ot emeli ki:

#include <functional>
#include <iostream>
using namespace std;

int main() {
    std::tr1::function<int (int, int)> f = std::plus<int>(); //C4996
    cout << f(3, 5) << std::endl;
    f = std::multiplies<int>();
    cout << f(3, 5) << std::endl;
}
warning C4996: 'std::tr1': warning STL4002: The non-standard std::tr1 namespace and TR1-only machinery are deprecated and will be REMOVED. You can define _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING to acknowledge that you have received this warning.

A hiba kijavításához távolítsa el a névtérre tr1 mutató hivatkozást:

#include <functional>
#include <iostream>
using namespace std;

int main() {
    std::function<int (int, int)> f = std::plus<int>();
    cout << f(3, 5) << std::endl;
    f = std::multiplies<int>();
    cout << f(3, 5) << std::endl;
}

A D. melléklet standard könyvtárfunkciói elavultként vannak megjelölve

Ha be van állítva a /std:c++17 mód- vagy újabb fordítókapcsoló, a D. melléklet szinte minden szabványos könyvtárfunkciója elavultként van megjelölve.

A Visual Studio 2017 15.5-ös verziójában a következő kód a C4996-ot emeli ki:

#include <iterator>

class MyIter : public std::iterator<std::random_access_iterator_tag, int> {
public:
    // ... other members ...
};

#include <type_traits>

static_assert(std::is_same<MyIter::pointer, int*>::value, "BOOM");
warning C4996: 'std::iterator<std::random_access_iterator_tag,int,ptrdiff_t,_Ty*,_Ty &>::pointer': warning STL4015: The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. (The <iterator> header is NOT deprecated.) The C++ standard has never required user-defined iterators to derive from std::iterator. To fix this warning, stop deriving from std::iterator and start providing publicly accessible typedefs named iterator_category, value_type, difference_type, pointer, and reference. Note that value_type is required to be non-const, even for constant iterators. You can define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning.

A hiba kijavításához kövesse a figyelmeztető szöveg utasításait, ahogyan az a következő kódban is látható:

#include <iterator>

class MyIter {
public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef int value_type;
    typedef ptrdiff_t difference_type;
    typedef int* pointer;
    typedef int& reference;

    // ... other members ...
};

#include <type_traits>

static_assert(std::is_same<MyIter::pointer, int*>::value, "BOOM");

Nem hivatkozott helyi változók

A Visual Studio 15.5-ben a C4189 figyelmeztetést ad ki több esetben, ahogy az alábbi kódban is látható:

void f() {
    char s[2] = {0}; // C4189. Either use the variable or remove it.
}
warning C4189: 's': local variable is initialized but not referenced

A hiba kijavításához távolítsa el a nem használt változót.

Egysoros megjegyzések

A Visual Studio 2017 15.5-ös verziójában a C4001 és c4179 figyelmeztetéseket a C fordító már nem bocsátja ki. Korábban csak a /Za fordítókapcsoló alatt lettek kibocsátva. A figyelmeztetésekre már nincs szükség, mert az egysoros megjegyzések c99 óta a C szabvány részét képezik.

/* C only */
#pragma warning(disable:4001) // C4619
#pragma warning(disable:4179)
// single line comment
//* single line comment */
warning C4619: #pragma warning: there is no warning number '4001'

Ha a kódnak nem kell visszafelé kompatibilisnek lennie, kerülje a figyelmeztetést a C4001 és a C4179 letiltásának eltávolításával. Ha a kódnak visszafelé kompatibilisnek kell lennie, akkor csak a C4619-et tiltsa le.

/* C only */

#pragma warning(disable:4619)
#pragma warning(disable:4001)
#pragma warning(disable:4179)

// single line comment
/* single line comment */

__declspec csatolással rendelkező extern "C" attribútumok

A Visual Studio korábbi verzióiban a fordító figyelmen kívül hagyta a __declspec(...) attribútumokat, amikor a __declspec(...)-et a extern "C" csatolási specifikáció előtt alkalmazták. Ez a viselkedés miatt olyan kód jött létre, amelyet a felhasználó nem tervezett, és lehetséges futtatókörnyezeti következményekkel jár. A C4768 figyelmeztetés a Visual Studio 15.3-s verziójában lett hozzáadva, de alapértelmezés szerint ki volt kapcsolva. A Visual Studio 2017 15.5-ös verziójában a figyelmeztetés alapértelmezés szerint engedélyezve van.

__declspec(noinline) extern "C" HRESULT __stdcall // C4768
warning C4768: __declspec attributes before linkage specification are ignored

A hiba kijavításához helyezze a csatolási specifikációt a __declspec attribútum elé:

extern "C" __declspec(noinline) HRESULT __stdcall

Ez az új C4768 figyelmeztetés a Visual Studio 2017 15.3-as vagy újabb verziójával (például 10.0.15063.0-s verzióval, más néven RS2 SDK-val) szállított Windows SDK-fejléceken jelenik meg. A Windows SDK-fejlécek (pontosabban az ShlObj.h és a ShlObj_core.h) későbbi verziói azonban ki lettek javítva, hogy ne okozzák a figyelmeztetést. Ha ezt a figyelmeztetést a Windows SDK fejléceiből látja, az alábbi műveleteket hajthatja végre:

  1. Váltson a Visual Studio 2017 15.5-ös verziójához kapott legújabb Windows SDK-ra.

  2. Kapcsolja ki a figyelmeztetést a Windows SDK fejléc-utasításának #include körül:

   #pragma warning (push)
   #pragma warning(disable:4768)
   #include <shlobj.h>
   #pragma warning (pop)

extern constexpr Kapcsolat

A Visual Studio korábbi verzióiban a fordító mindig adott egy constexpr változó belső kapcsolatát, még akkor is, ha a változót megjelölték extern. A Visual Studio 2017 15.5-ös verziójában egy új fordítókapcsoló (/Zc:externConstexpr) lehetővé teszi a helyes, szabványoknak megfelelő működést. Végül ez a viselkedés lesz az alapértelmezett.

extern constexpr int x = 10;
error LNK2005: "int const x" already defined

Ha egy fejlécfájl deklarált változót extern constexprtartalmaz, meg kell jelölni __declspec(selectany) , hogy az ismétlődő deklarációk megfelelően legyenek kombinálva:

extern constexpr __declspec(selectany) int x = 10;

typeid nem használható hiányos osztálytípuson

A Visual Studio korábbi verzióiban a fordító helytelenül engedélyezte a következő kódot, ami esetleg helytelen típusadatokat eredményezett. A Visual Studio 2017 15.5-ös verziójában a fordító helyesen jelez hibát:

#include <typeinfo>

struct S;

void f() { typeid(S); } //C2027 in 15.5
error C2027: use of undefined type 'S'

std::is_convertible céltípus

std::is_convertible a céltípusnak érvényes visszatérési típusnak kell lennie. A Visual Studio korábbi verzióiban a fordító helytelenül engedélyezte az absztrakt típusokat, ami helytelen túlterhelésfeloldáshoz és nem tervezett futtatókörnyezeti viselkedéshez vezethet. A következő kód helyesen emeli ki a C2338-at:

#include <type_traits>

struct B { virtual ~B() = 0; };
struct D : public B { virtual ~D(); };

static_assert(std::is_convertible<D, B>::value, "fail"); // C2338 in 15.5

A hiba elkerülése érdekében a is_convertible használatakor hasonlítsa össze a mutatótípusokat, mert a nem mutató típusú összehasonlítás meghiúsulhat, ha egy típus absztrakt.

#include <type_traits>

struct B { virtual ~B() = 0; };
struct D : public B { virtual ~D(); };

static_assert(std::is_convertible<D *, B *>::value, "fail");

Dinamikus kivétel specifikáció eltávolítása és noexcept

A C++17-ben a throw() egy aliasa a noexcept-nak, a throw(<type list>) és throw(...) eltávolításra kerültek, és bizonyos típusok tartalmazhatnak noexcept. Ez a módosítás forráskompatibilitási problémákat okozhat a C++14 vagy korábbi verziónak megfelelő kóddal. A /Zc:noexceptTypes- kapcsolóval visszatérhet a C++14 verzióra noexcept, miközben általában a C++17 módot használja. Lehetővé teszi, hogy a forráskódot úgy frissítse, hogy megfeleljen a C++17-nek anélkül, hogy egyszerre kellene átírnia az throw() összes kódot.

A fordító mostantól a C++17 mód vagy a /permissive- használatakor is diagnosztizálja az eltérő kivétel-specifikációkat az új C5043 figyelmeztetéssel.

A következő kód létrehozza a C5043-at és a C5040-et a Visual Studio 2017 15.5-ös verziójában a /std:c++17 kapcsoló alkalmazásakor:

void f() throw(); // equivalent to void f() noexcept;
void f() {} // warning C5043
void g() throw(); // warning C5040

struct A {
    virtual void f() throw();
};

struct B : A {
    virtual void f() { } // error C2694
};

Ha el szeretné távolítani a hibákat a /std:c++17 használata közben, adja hozzá a /Zc:noexceptTypes- kapcsolót a parancssorhoz, vagy frissítse a kódot a noexcept használatára, ahogyan az alábbi példában látható.

void f() noexcept;
void f() noexcept { }
void g() noexcept(false);

struct A {
    virtual void f() noexcept;
};

struct B : A {
    virtual void f() noexcept { }
};

Beágyazott változók

A statikus constexpr adattagok mostantól implicit módon vannak meghatározva inline, ami azt jelenti, hogy az osztályon belüli deklarációjuk most már a definíciójuk. Az static constexpr adattag külön definiálásának használata redundáns, és immár elavult. A Visual Studio 2017 15.5-ös verziójában, amikor a /std:c++17 kapcsolót alkalmazza, a következő kód a C5041 figyelmeztetést eredményez:

struct X {
    static constexpr int size = 3;
};
const int X::size; // C5041: 'size': out-of-line definition for constexpr static data member is not needed and is deprecated in C++17

extern "C" __declspec(...) figyelmeztetés: A C4768 alapértelmezés szerint be van kapcsolva

A figyelmeztetés a Visual Studio 2017 15.3-s verziójában lett hozzáadva, de alapértelmezés szerint ki volt kapcsolva. A Visual Studio 2017 15.5-ös verziójában a figyelmeztetés alapértelmezés szerint be van kapcsolva. További információt az attribútumokra vonatkozó __declspec Új figyelmeztetés című témakörben talál.

Alapértelmezett függvények és __declspec(nothrow)

A fordító korábban engedélyezte az alapértelmezett függvények __declspec(nothrow) szintaxissal való deklarálását, amikor a megfelelő alap- vagy tagfüggvények kivételeket engedélyeztek. Ez a viselkedés ellentétes a C++ szabványéval, és futásidőben nem definiált viselkedést okozhat. A szabvány megköveteli az ilyen függvények törlését, ha a kivétel specifikációja nem egyezik. A következő /std:c++17kód a C2280-at emeli ki:

struct A {
    A& operator=(const A& other) { // No exception specification; this function may throw.
        ...
    }
};

struct B : public A {
    __declspec(nothrow) B& operator=(const B& other) = default;
};

int main()
{
    B b1, b2;
    b2 = b1; // error C2280: attempting to reference a deleted function.
             // Function was implicitly deleted because the explicit exception
             // specification is incompatible with that of the implicit declaration.
}

A kód kijavításához távolítsa el a __declspec(nothrow) függvényt az alapértelmezett függvényből, vagy távolítsa el = default és adja meg a függvény definícióját a szükséges kivételkezeléssel együtt:

struct A {
    A& operator=(const A& other) {
        // ...
    }
};

struct B : public A {
    B& operator=(const B& other) = default;
};

int main()
{
    B b1, b2;
    b2 = b1;
}

noexcept és részleges specializációk

A noexcept típusrendszerben előfordulhat, hogy a meghatározott 'hívható' típusokra illeszkedő részleges specializációk nem fordíthatók le, vagy nem választják az elsődleges sablont, mert hiányzik a noexcept tulajdonsággal rendelkező függvénymutatók részleges specializációja.

Ilyen esetekben előfordulhat, hogy további részleges specializációkat kell hozzáadnia a függvénymutatók és a tagfüggvények mutatóinak kezeléséhez. Ezek a túlterhelések csak /std:c++17 vagy újabb módban megengedettek. Ha a C++14 specifikációval való visszamenőleges kompatibilitást fenn kell tartani, és mások által használt kódot írsz, akkor ezeket az új túlterheléseket #ifdef direktívákon belül érdemes védeni. Ha önálló és zárt modulban dolgozik, akkor #ifdef őrök helyett egyszerűen lefordíthat a /Zc:noexceptTypes- kapcsolóval.

A következő kód lefordul /std:c++14 alatt, de nem sikerül /std:c++17 alatt a C2027 hibával:

template <typename T> struct A;

template <>
struct A<void(*)()>
{
    static const bool value = true;
};

template <typename T>
bool g(T t)
{
    return A<T>::value;
}

void f() noexcept {}

int main()
{
    return g(&f) ? 0 : 1; // C2027: use of undefined type 'A<T>'
}

Mivel a fordító az új részleges specializációt A<void (*)() noexcept> választja, a következő kód /std:c++17 sikeres.

template <typename T> struct A;

template <>
struct A<void(*)()>
{
    static const bool value = true;
};

template <>
struct A<void(*)() noexcept>
{
    static const bool value = true;
};

template <typename T>
bool g(T t)
{
    return A<T>::value;
}

void f() noexcept {}

int main()
{
    return g(&f) ? 0 : 1; // OK
}

Megfelelőségi fejlesztések a 15.6-os verzióban

C++17 Könyvtár alapjai V1

P0220R1 tartalmazza a C++17 könyvtár alapjai műszaki specifikációját a szabványba. A következő frissítéseket ismerteti: <experimental/tuple>, <experimental/optional>, <experimental/functional>, <experimental/any>, <experimental/string_view>, <experimental/memory><experimental/memory_resource>, és <experimental/algorithm>.

C++17: Az osztálysablon argumentumlevonásának javítása a standard kódtár esetében

P0739R0 Helyezze át adopt_lock_t a paraméterlista elejére scoped_lock, hogy lehetővé tegye a scoped_lock konzisztens használatát. A másolás-hozzárendelés engedélyezéséhez a std::variant konstruktor több esetben is részt vehet a túlterhelés feloldásában.

Megfelelőségi javítások a 15.7-ben

C++17: Öröklő konstruktorok újrafogalmazása

P0136R1 azt határozza meg, hogy a using konstruktor nevét tartalmazó deklaráció mostantól láthatóvá teszi a megfelelő alaposztály-konstruktorokat a származtatott osztály inicializálásai számára, nem pedig származtatottabb osztálykonstruktorokat deklarál. Ez az újrafogalmazás egy változtatás a C++14-hez képest. A Visual Studio 2017 15.7-es és újabb verzióiban, a /std:c++17 üzemmódban, a C++14-ben érvényes, öröklő konstruktorokat használó kód nem biztos, hogy érvényes, vagy esetleg eltérő szemantikával rendelkezik.

Az alábbi példa c++14 viselkedést mutat be:

struct A {
    template<typename T>
    A(T, typename T::type = 0);
    A(int);
};

struct B : A {
    using A::A;
    B(int n) = delete; // Error C2280
};

B b(42L); // Calls B<long>(long), which calls A(int)
          //  due to substitution failure in A<long>(long).

Az alábbi példa bemutatja a /std:c++17 viselkedését a Visual Studio 15.7-ben.

struct A {
    template<typename T>
    A(T, typename T::type = 0);
    A(int);
};

struct B : A {
    using A::A;
    B(int n)
    {
        //do something
    }
};

B b(42L); // now calls B(int)

További információ: Konstruktorok.

C++17: Kiterjesztett aggregátum-inicializálás

P0017R1

Ha az alaposztály konstruktora nem nyilvános, de egy származtatott osztály számára elérhető, akkor /std:c++17 a Visual Studio 2017 15.7-es verziójában a továbbiakban nem használhat üres zárójeleket a származtatott típusú objektumok inicializálásához. Az alábbi példa a C++14-nek megfelelő viselkedést mutatja be:

struct Derived;
struct Base {
    friend struct Derived;
private:
    Base() {}
};

struct Derived : Base {};
Derived d1; // OK. No aggregate init involved.
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
               // which can call Base ctor.

A C++17-ben Derived mostantól összesített típusnak számít. Ez azt jelenti, hogy a privát alapértelmezett konstruktoron keresztüli Base inicializálás közvetlenül történik a kiterjesztett összesítési inicializálási szabály részeként. Korábban a Base magánkonstruktort a Derived konstruktoron keresztül hívták meg, és a barát deklarációja miatt sikerült. Az alábbi példa a C++17 viselkedést mutatja be a Visual Studio 15.7-es verziójában /std:c++17 módban:

struct Derived;
struct Base {
    friend struct Derived;
private:
    Base() {}
};
struct Derived : Base {
    Derived() {} // add user-defined constructor
                 // to call with {} initialization
};
Derived d1; // OK. No aggregate init involved.
Derived d2 {}; // error C2248: 'Base::Base': cannot access
               // private member declared in class 'Base'

C++17: Nem típusú sablonparaméterek deklarálása automatikusan

P0127R2

Módban /std:c++17 a fordító mostantól a következővel deklarált autonem típusú sablonargumentum típusát tudja következtetni:

template <auto x> constexpr auto constant = x;

auto v1 = constant<5>;      // v1 == 5, decltype(v1) is int
auto v2 = constant<true>;   // v2 == true, decltype(v2) is bool
auto v3 = constant<'a'>;    // v3 == 'a', decltype(v3) is char

Ennek az új funkciónak az egyik hatása, hogy az érvényes C++14 kód érvénytelen, vagy eltérő szemantikával rendelkezik. A korábban érvénytelen túlterhelések például érvényesek. Az alábbi példa C++14 kódot mutat be, amely lefordítható, mert a hívás example(p) össze van kötve example(void*);-hez. A Visual Studio 2017 15.7-es verziójában a /std:c++17 módban a example függvénysablon a legjobb egyezés.

template <int N> struct A;
template <typename T, T N> int example(A<N>*) = delete;

void example(void *);

void sample(A<0> *p)
{
    example(p); // OK in C++14
}

Az alábbi példa C++17 kódot mutat be a Visual Studio 15.7-ben /std:c++17 módban:

template <int N> struct A;
template <typename T, T N> int example(A<N>*);

void example(void *);

void sample(A<0> *p)
{
    example(p); // C2280: 'int example<int,0>(A<0>*)': attempting to reference a deleted function
}

C++17: Elemi sztringátalakítások (részleges)

P0067R5 Alacsony szintű, helyfüggetlen függvények az egész számok és karakterláncok, valamint a lebegőpontos számok és karakterláncok közötti konvertáláshoz.

C++20: A felesleges bomlás elkerülése (részleges)

P0777R1 Különbséget ad a "bomlás" fogalma és a const vagy referencia-minősítők egyszerű eltávolítása között. Az új típustulajdonság remove_reference_t lecseréli a decay_t-t bizonyos kontextusokban. remove_cvref_t A támogatás a Visual Studio 2019-ben implementálva van.

C++17: Párhuzamos algoritmusok

P0024R2 A Parallelism TS kisebb módosításokkal be van építve a szabványba.

C++17: hypot(x, y, z)

P0030R1 Három új túlterhelést std::hypotad hozzá a típusokhozfloatdouble, és long doublemindegyikhez három bemeneti paraméter tartozik.

C++17: <filesystem>

P0218R1 Néhány szövegmódosítással bevezeti a fájlrendszer TS-t a szabványba.

C++17: Matematikai speciális függvények

P0226R1 A matematikai speciális függvények korábbi műszaki specifikációit fogadja el a standard <cmath> fejlécben.

C++17: A standard kódtárhoz tartozó levonási útmutatók

P0433R2 Az STL frissítései a P0091R3 C++17 bevezetésének előnyeinek kihasználásához, amely támogatja az osztálysablon argumentumlevonását.

C++17: Elemi sztringátalakítások javítása

P0682R1 Helyezze át az új elemi karakterlánc-konvertálási függvényeket a P0067R5-ből egy új fejlécbe <charconv>, és végezzen el további fejlesztéseket, például módosítsa a hibakezelést úgy, hogy a std::errc-t használja a std::error_code helyett.

C++17: constexprchar_traits (részleges)

P0426R1 Változtatások a std::traits_type tagfüggvényeken length, compare, és find annak érdekében, hogy std::string_view használható legyen az állandó kifejezésekben. (A Visual Studio 2017 15.6-os verziójában csak a Clang/LLVM támogatott. A 15.7-es verzióban a ClXX támogatása is majdnem teljes.)

C++17: Alapértelmezett argumentum az elsődleges osztálysablonban

Ez a viselkedésváltozás előfeltétele a P0091R3 - Template argument deduction for class templates-nek.

Korábban a fordító figyelmen kívül hagyta az elsődleges osztálysablon alapértelmezett argumentumát:

template<typename T>
struct S {
    void f(int = 0);
};

template<typename T>
void S<T>::f(int = 0) {} // Re-definition necessary

A /std:c++17 Visual Studio 2017 15.7-es verziójának módban a rendszer nem hagyja figyelmen kívül az alapértelmezett argumentumot:

template<typename T>
struct S {
    void f(int = 0);
};

template<typename T>
void S<T>::f(int) {} // Default argument is used

Függő névfeloldás

Ez a viselkedésváltozás előfeltétele a következőnek P0091R3 - Template argument deduction for class templates: .

Az alábbi példában a Visual Studio 15.6-os és korábbi verzió fordítója az elsődleges osztálysablonban a D::type elemet B<T>::type elemre oldja fel.

template<typename T>
struct B {
    using type = T;
};

template<typename T>
struct D : B<T*> {
    using type = B<T*>::type;
};

A Visual Studio 2017 15.7-es verziója, /std:c++17 módban, megköveteli a typename kulcsszót a using utasításban D esetén. Ha nincs typename, a fordító figyelmeztetést ad a C4346-ra, és C2061 hibát okoz: 'B<T*>::type': dependent name is not a type: syntax error: identifier 'type'.

template<typename T>
struct B {
    using type = T;
};

template<typename T>
struct D : B<T*> {
    using type = typename B<T*>::type;
};

C++17: [[nodiscard]] attribútum – figyelmeztetési szint növelése

A Visual Studio 2017 15.7-es verziójában /std:c++17 módban a C4834 figyelmeztetési szintje W3-ról W1-re nő. Letilthatja a figyelmeztetést egy leadott üzenettel void, vagy a fordítónak való átadással /wd:4834 .

[[nodiscard]] int f() { return 0; }

int main() {
    f(); // warning C4834: discarding return value
         // of function with 'nodiscard'
}

Variadikus sablonkonstruktor alaposztály inicializálási listája

A Visual Studio korábbi kiadásaiban hiba nélkül engedélyezve volt egy variadikus sablonkonstruktor alaposztály inicializálási listája, amely nem tartalmazott sablonargumentumokat. A Visual Studio 2017 15.7-es verziójában fordítóhiba lépett fel.

A Visual Studio 2017 15.7-es verziójában az alábbi példakód c2614-es hibát jelez:

template<typename T>
struct B {};

template<typename T>
struct D : B<T>
{

    template<typename ...C>
    D() : B() {} // C2614: D<int>: illegal member initialization: 'B' is not a base or member
};

D<int> d;

A hiba kijavításához változtassa meg a B() kifejezést B<T>()-re.

constexpr aggregátum inicializálása

A C++ fordító korábbi verziói helytelenül kezeltek constexpr összesített inicializálást. A fordító érvénytelen kódot fogadott el, amelyben az összesítő-init-lista túl sok elemet tartalmazott, és rossz objektumkódot eredményezett. Az alábbi kód egy példa az ilyen kódra:

#include <array>
struct X {
    unsigned short a;
    unsigned char b;
};

int main() {
    constexpr std::array<X, 2> xs = { // C2078: too many initializers
        { 1, 2 },
        { 3, 4 }
    };
    return 0;
}

A Visual Studio 2017 15.7 3.7-es és újabb verziójában az előző példa most a C2078-at emeli ki. Az alábbi példa bemutatja, hogyan lehet kijavítani a kódot. Amikor kapcsos zárójeles init-listákkal inicializál egy std::array-ot, a belső tömbnek adjunk meg egy saját kapcsos zárójeles listát:

#include <array>
struct X {
    unsigned short a;
    unsigned char b;
};

int main() {
    constexpr std::array<X, 2> xs = {{ // note double braces
        { 1, 2 },
        { 3, 4 }
    }}; // note double braces
    return 0;
}

Megfelelőségi fejlesztések a 15.8-ban

typename a nem minősített azonosítókról

/permissive- módban az aliassablon-definíciók nem minősített azonosítóinak hamis typename kulcsszavait a fordítóprogram már nem fogadja el. A következő kód mostantól C7511-et hoz létre:

template <typename T>
using  X = typename T; // C7511: 'T': 'typename' keyword must be
                       // followed by a qualified name

A hiba kijavításához módosítsa a második sort a következőre using X = T;: .

__declspec() az aliassablon-definíciók jobb oldalán

__declspec az aliassablon-definíció jobb oldalán már nem engedélyezett. Korábban a fordító elfogadta, de figyelmen kívül hagyta ezt a kódot. Ez soha nem eredményezne érvénytelenítési figyelmeztetést az alias használatakor.

Ehelyett a standard C++ attribútum [[deprecated]] használható, és a Visual Studio 2017 15.6-os verziójában is érvényes. A következő kód most c2760-et állít elő:

template <typename T>
using X = __declspec(deprecated("msg")) T; // C2760: syntax error:
                                           // unexpected token '__declspec',
                                           // expected 'type specifier'

A hiba kijavításához módosítsa a kódot a következőre (az aliasdefiníció '=' elé helyezett attribútummal):

template <typename T>
using  X [[deprecated("msg")]] = T;

Kétfázisú névkeresési diagnosztika

A kétfázisú névkereséshez a sablontestekben használt nem függő neveknek a definíció időpontjában láthatónak kell lenniük a sablon számára. Korábban a Microsoft C++ fordító egy nem található nevet hagyott, amelyet csak a példányosításkor keresett ki. Most azt követeli meg, hogy a nem függő nevek meg legyenek kötve a sablon törzsében.

Ennek egyik megnyilvánulási módja a függő alaposztályokba való betekintés. Korábban a fordító engedélyezte a függő alaposztályokban definiált nevek használatát. Ennek az az oka, hogy az összes típus feloldásakor a példányosítás során keresik őket. Most a kód hibaként lesz kezelve. Ezekben az esetekben kényszerítheti a változót a példányi idő megtekintésére az alaposztály típusának minősítésével, vagy más módon függővé tételével, például mutató this-> hozzáadásával.

Módban /permissive- az alábbi kód most a C3861-et emeli ki:

template <class T>
struct Base {
    int base_value = 42;
};

template <class T>
struct S : Base<T> {
    int f() {
        return base_value; // C3861: 'base_value': identifier not found
    }
};

A hiba kijavításához módosítsa a return utasítást return this->base_value;-ra.

Megjegyzés:

A Boost.Python könyvtár 1.70 előtti verzióiban egy MSVC-specifikus kerülő megoldás található a sablontovábbítási deklarációhoz a unwind_type.hpp-ban. A /permissive- Visual Studio 2017 15.8-es verziójától (_MSC_VER==1915) kezdődő módban az MSVC fordító helyesen végzi el az argumentumfüggő névkeresést (ADL). Most már összhangban áll más fordítókkal, így ez a védő megkerülő megoldás szükségtelen. A C3861 hiba 'unwind_type': identifier not foundelkerülése érdekében frissítse a Boost.Python-kódtárat.

deklarációk és definíciók továbbítása a névtérben std

A C++ szabvány nem teszi lehetővé, hogy a felhasználó előre deklarációkat vagy definíciókat adjon hozzá a névtérhez std. Ha deklarációkat vagy definíciókat ad hozzá a névtérhez std vagy egy névtéren belüli névtérhez std , az nem definiált viselkedést eredményez.

A Microsoft a jövőben valamikor áthelyezi azt a helyet, ahol bizonyos szabványos kódtártípusok definiálva vannak. Ez a módosítás megszünteti a meglévő kódot, amely előre deklarációkat ad hozzá a std névtérhez. A C4643 nevű új figyelmeztetés segít azonosítani az ilyen forrásproblémákat. A figyelmeztetés a(z) /default módban engedélyezett, és alapértelmezés szerint ki van kapcsolva. Ez hatással lesz azokra a programokra, amelyek le vannak fordítva /Wall vagy /WX-vel.

A következő kód most a C4643-at emeli ki:

namespace std {
    template<typename T> class vector;  // C4643: Forward declaring 'vector'
                                        // in namespace std is not permitted
                                        // by the C++ Standard
}

A hiba kijavításához használjon direktívát #include a továbbítási deklaráció helyett:

#include <vector>

Önmaguknak delegált konstruktorok

A C++ szabvány azt javasolja, hogy a fordítónak diagnosztikát kell kibocsátania, ha egy delegáló konstruktor delegálja magát. A Microsoft C++ fordító /std:c++17 és /std:c++latest módban mostantól C7535 figyelmeztetést ad.

A hiba nélkül a következő program lefordítja, de végtelen ciklust hoz létre:

class X {
public:
    X(int, int);
    X(int v) : X(v){} // C7535: 'X::X': delegating constructor calls itself
};

A végtelen hurok elkerülése érdekében delegáljon egy másik konstruktort:

class X {
public:

    X(int, int);
    X(int v) : X(v, 0) {}
};

offsetof állandó kifejezésekkel

offsetof hagyományosan egy olyan makróval lett implementálva, amely egy reinterpret_cast. Ez a használat nem engedélyezett olyan környezetekben, amelyek állandó kifejezést igényelnek, de a Microsoft C++ fordítója hagyományosan engedélyezte. A offsetof standard kódtár részeként szállított makró helyesen használ fordító belsőt (__builtin_offsetof), de sokan használták a makró trükköt a sajátjuk offsetofdefiniálásához.

A Visual Studio 2017 15.8-s verziójában a fordító korlátozza azokat a területeket, amelyeket ezek reinterpret_cast az operátorok az alapértelmezett módban is megjeleníthetnek, hogy a kód megfeleljen a normál C++ viselkedésnek. Ez alatt /permissive-a korlátozások még szigorúbbak. Az állandó kifejezéseket igénylő helyek eredményének offsetof használata c4644-es vagy C2975-ös figyelmeztetést eredményez.

Az alábbi kód a C4644 figyelmeztetést adja alapértelmezett és /std:c++17 módokban, a C2975 figyelmeztetést pedig /permissive- módban.

struct Data {
    int x;
};

// Common pattern of user-defined offsetof
#define MY_OFFSET(T, m) (unsigned long long)(&(((T*)nullptr)->m))

int main()

{
    switch (0) {
    case MY_OFFSET(Data, x): return 0; // C4644: usage of the
        // macro-based offsetof pattern in constant expressions
        // is non-standard; use offsetof defined in the C++
        // standard library instead
        // OR
        // C2975: invalid template argument, expected
        // compile-time constant expression

    default: return 1;
    }
}

A hiba kijavításához használja offsetof a <cstddef> által meghatározottak szerint.

#include <cstddef>

struct Data {
    int x;
};

int main()
{
    switch (0) {
    case offsetof(Data, x): return 0;
    default: return 1;
    }
}

cv-minősítők a csomagbővítés hatálya alá tartozó alaposztályokon

A Microsoft C++ fordító korábbi verziói nem észlelték, hogy egy ősosztály rendelkezik cv-kvalifikátorokkal, ha a csomagbővítés is vonatkozik rá.

A Visual Studio 2017 15.8-as verziójában /permissive- módban a következő kód a C3770-es hibát generálja.

template<typename... T>
class X : public T... { };

class S { };

int main()
{
    X<const S> x; // C3770: 'const S': is not a valid base class
}

template kulcsszavak és beágyazott névkijelölők

A /permissive- módban a fordító megköveteli, hogy a template kulcsszó megelőzze a sablonnevet, ha egy függőben lévő beágyazott azonosító után szerepel.

A következő módban lévő /permissive- kód most a C7510-et emeli ki:

template<typename T> struct Base
{
    template<class U> void example() {}
};

template<typename T>
struct X : Base<T>
{
    void example()
    {
        Base<T>::example<int>(); // C7510: 'example': use of dependent
            // template name must be prefixed with 'template'
            // note: see reference to class template instantiation
            // 'X<T>' being compiled
    }
};

A hiba kijavításához adja hozzá a template kulcsszót az Base<T>::example<int>(); utasításhoz az alábbi példában látható módon:

template<typename T> struct Base
{
    template<class U> void example() {}
};

template<typename T>
struct X : Base<T>
{
    void example()
    {
        // Add template keyword here:
        Base<T>::template example<int>();
    }
};

Megfelelőségi fejlesztések a 15.9-ben

Balról jobbra történő kiértékelési sorrend operátorok ->*, [], >>, és <<

A C++17-től kezdődően az operátorok ->*[]>><< operandusait balról jobbra sorrendben kell kiértékelni. Két esetben a fordító nem tudja garantálni ezt a sorrendet:

  • ha az operandus-kifejezések egyike érték által átadott objektum, vagy érték által átadott objektumot tartalmaz, vagy

  • /clr használatával történő fordításkor, ha az operandusok egyike egy objektum vagy tömb elem mezője.

A fordító figyelmeztetést ad ki a C4866-ról , ha nem tudja garantálni a balról jobbra történő értékelést. A fordító csak akkor hozza létre ezt a figyelmeztetést, ha /std:c++17 vagy később van megadva, mivel az operátorok balról jobbra sorrendre vonatkozó követelménye a C++17-ben lett bevezetve.

A figyelmeztetés megoldásához először fontolja meg, hogy szükség van-e az operandusok balról jobbra történő kiértékelésére. Szükség lehet például arra, hogy az operandusok kiértékelése rendelésfüggő mellékhatásokat eredményezhet. Az operandusok kiértékelési sorrendjének sok esetben nincs megfigyelhető hatása. Ha a kiértékelési sorrendnek balról jobbra kell lennie, fontolja meg, hogy át tudja-e adni az operandusokat const hivatkozással. Ez a módosítás megszünteti a következő kódmintában szereplő figyelmeztetést:

// C4866.cpp
// compile with: /w14866 /std:c++17

class HasCopyConstructor
{
public:
    int x;

    HasCopyConstructor(int x) : x(x) {}
    HasCopyConstructor(const HasCopyConstructor& h) : x(h.x) { }
};

int operator>>(HasCopyConstructor a, HasCopyConstructor b) { return a.x >> b.x; }

// This version of operator>> does not trigger the warning:
// int operator>>(const HasCopyConstructor& a, const HasCopyConstructor& b) { return a.x >> b.x; }

int main()
{
    HasCopyConstructor a{ 1 };
    HasCopyConstructor b{ 2 };

    a>>b;        // C4866 for call to operator>>
};

Tagok aliassablonjaiban lévő azonosítók

A tag aliassablon-definíciójában használt azonosítót használat előtt deklarálni kell.

A fordító korábbi verzióiban a következő kód lett engedélyezve. A Visual Studio 2017 15.9-es verziójában /permissive- a fordító a C3861-et emeli ki:

template <typename... Ts>
struct A
{
  public:
    template <typename U>
    using from_template_t = decltype(from_template(A<U>{})); // C3861:
        // 'from_template': identifier not found

  private:
    template <template <typename...> typename Type, typename... Args>
    static constexpr A<Args...> from_template(A<Type<Args...>>);
};

A<>::from_template_t<A<int>> a;

A hiba kijavításához deklaráljon from_template korábban from_template_t.

Modulok változásai

A Visual Studio 2017 15.9-es verziójában a fordító c5050-et állít elő, amikor a modulok parancssori beállításai nem konzisztensek a modullétrehozás és a modulhasználati oldal között. Az alábbi példában két probléma van:

  • A fogyasztási oldalon (main.cpp) nincs megadva a beállítás /EHsc.

  • A C++ verzió /std:c++17 a létrehozási oldalon, és /std:c++14 a felhasználási oldalon van.

cl /EHsc /std:c++17 m.ixx /experimental:module
cl /experimental:module /module:reference m.ifc main.cpp /std:c++14

A fordító mindkét esetben a C5050-et emeli:

warning C5050: Possible incompatible environment while
importing module 'm': mismatched C++ versions.
Current "201402" module version "201703".

A fordító emellett c7536-ot is emel, ha a .ifc fájlt illetéktelenek módosították. A modul felületének fejléce az alatta lévő tartalom SHA2 kivonatát tartalmazza. Importáláskor a rendszer kivonatolja a .ifc fájlt, majd ellenőrzi a fejlécben megadott kivonatot. Ha ezek nem egyeznek, a C7536 hiba jelenik meg:

error C7536: ifc failed integrity checks.
Expected SHA2: '66d5c8154df0c71d4cab7665bab4a125c7ce5cb9a401a4d8b461b706ddd771c6'

Aliasokat és nem dedukált környezeteket tartalmazó részleges rendezés

A implementációk eltérnek a részleges rendezési szabályokban, amelyek az aliasokat nem dedukált környezetekben tartalmazzák. Az alábbi példában a GCC és a Microsoft C++ fordítóprogram (a /permissive- módban) hibát jelez, míg a Clang elfogadja a kódot.

#include <utility>
using size_t = std::size_t;

template <typename T>
struct A {};
template <size_t, size_t>
struct AlignedBuffer {};
template <size_t len>
using AlignedStorage = AlignedBuffer<len, 4>;

template <class T, class Alloc>
int f(Alloc &alloc, const AlignedStorage<T::size> &buffer)
{
    return 1;
}

template <class T, class Alloc>
int f(A<Alloc> &alloc, const AlignedStorage<T::size> &buffer)
{
    return 2;
}

struct Alloc
{
    static constexpr size_t size = 10;
};

int main()
{
    A<void> a;
    AlignedStorage<Alloc::size> buf;
    if (f<Alloc>(a, buf) != 2)
    {
        return 1;
    }

    return 0;
}

Az előző példa a C2668-at emeli ki:

partial_alias.cpp(32): error C2668: 'f': ambiguous call to overloaded function
partial_alias.cpp(18): note: could be 'int f<Alloc,void>(A<void> &,const AlignedBuffer<10,4> &)'
partial_alias.cpp(12): note: or       'int f<Alloc,A<void>>(Alloc &,const AlignedBuffer<10,4> &)'
        with
        [
            Alloc=A<void>
        ]
partial_alias.cpp(32): note: while trying to match the argument list '(A<void>, AlignedBuffer<10,4>)'

A megvalósítás eltérése a C++ szabványszöveg regressziójának köszönhető. A 2235-ös alapvető probléma megoldása eltávolított néhány szöveget, amelyek lehetővé tennék a túlterhelések rendezését. A jelenlegi C++ szabvány nem biztosít mechanizmust a függvények részleges rendezéséhez, ezért nem egyértelműnek tekinthetők.

Egy megoldásként azt javasoljuk, hogy ne támaszkodjon a részleges sorrendre a probléma megoldásához. Ehelyett az SFINAE használatával távolítson el bizonyos túlterheléseket. Az alábbi példában egy segédosztály IsA használatával távolítjuk el az első túlterhelést, ha Alloc a A specializációja.

#include <utility>
using size_t = std::size_t;

template <typename T>
struct A {};
template <size_t, size_t>
struct AlignedBuffer {};
template <size_t len>
using AlignedStorage = AlignedBuffer<len, 4>;

template <typename T> struct IsA : std::false_type {};
template <typename T> struct IsA<A<T>> : std::true_type {};

template <class T, class Alloc, typename = std::enable_if_t<!IsA<Alloc>::value>>
int f(Alloc &alloc, const AlignedStorage<T::size> &buffer)
{
    return 1;
}

template <class T, class Alloc>
int f(A<Alloc> &alloc, const AlignedStorage<T::size> &buffer)
{
    return 2;
}

struct Alloc
{
    static constexpr size_t size = 10;
};

int main()
{
    A<void> a;
    AlignedStorage<Alloc::size> buf;
    if (f<Alloc>(a, buf) != 2)
    {
        return 1;
    }

    return 0;
}

Érvénytelen kifejezések és nem literális típusok sablonfüggvény-definíciókban

Az illegális kifejezések és a nem literális típusok már helyesen vannak diagnosztizálva a kifejezetten specializált sablonfüggvények definícióiban. Korábban ezek a hibák nem lettek kibocsátva a függvénydefiníció esetében. Az illegális kifejezés vagy a nem literális típus azonban továbbra is diagnosztizálva lett volna, ha egy állandó kifejezés részeként lett kiértékelve.

A Visual Studio korábbi verzióiban a következő kód fordítja le figyelmeztetés nélkül:

void g();

template<typename T>
struct S
{
    constexpr void f();
};

template<>
constexpr void S<int>::f()
{
    g(); // C3615 in 15.9
}

A Visual Studio 2017 15.9-es verziójában a kód C3615-ös hibát jelez:

error C3615: constexpr function 'S<int>::f' cannot result in a constant expression.
note: failure was caused by call of undefined function or one not declared 'constexpr'
note: see usage of 'g'.

A hiba elkerülése érdekében távolítsa el a constexpr minősítőt a függvény f()explicit példányából.

Lásd még

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