Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A 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:
Váltson a Visual Studio 2017 15.5-ös verziójához kapott legújabb Windows SDK-ra.
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
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
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
/clrhaszná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++17a létrehozási oldalon, és/std:c++14a 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.