Visual Studio 2017'de C++ Uyumluluk geliştirmeleri, davranış değişiklikleri ve hata düzeltmeleri
Visual Studio'da (MSVC) Microsoft C/C++ her sürümde uyumluluk iyileştirmeleri ve hata düzeltmeleri yapar. Bu makalede, ana sürüme ve ardından sürüme göre iyileştirmeler listelenir. Belirli bir sürümdeki değişikliklere doğrudan geçmek için bu makaledeki aşağıdaki listeyi kullanın.
Bu belgede Visual Studio 2017'deki değişiklikler listelenir. Visual Studio 2022'deki değişikliklere yönelik bir kılavuz için bkz . Visual Studio 2022'de C++ uyumluluk geliştirmeleri. Visual Studio 2019'daki değişikliklere yönelik bir kılavuz için bkz . Visual Studio 2019'da C++ uyumluluk geliştirmeleri. Önceki uyumluluk iyileştirmelerinin tam listesi için bkz . Visual C++ Yenilikler 2003 ile 2015 arasında.
Visual Studio 2017 RTW'de uyumluluk geliştirmeleri (sürüm 15.0)
Toplamalar için genelleştirilmiş constexpr
ve statik olmayan veri üyesi başlatma (NSDMI) desteğiyle, Visual Studio 2017'deki MSVC derleyicisi artık C++14 standardına eklenen özellikler için tamamlanmıştır. Ancak, derleyici C++11 ve C++98 standartlarından birkaç özelliğe sahip değildir. Bkz. Derleyicinin geçerli durumu için Microsoft C/C++ dil uyumluluğu .
C++11: Daha fazla kitaplıkta İfade SFINAE desteği
Derleyici, SFINAE ifadesi desteğini geliştirmeye devam eder. Ve ifadelerinin şablon parametreleri olarak görünebileceği şablon bağımsız değişken kesintisi ve constexpr
değiştirme decltype
için gereklidir. Daha fazla bilgi için bkz . Visual Studio 2017 RC'de İfade SFINAE geliştirmeleri.
C++14: Toplamalar için NSDMI
Toplama, kullanıcı tarafından sağlanan oluşturucu, özel veya korumalı statik olmayan veri üyeleri, temel sınıflar ve sanal işlevler içermeyen bir dizi veya sınıftır. C++14 sürümünden başlayarak, toplamalar üye başlatıcıları içerebilir. Daha fazla bilgi için bkz . Üye başlatıcılar ve toplamalar.
C++14: Genişletilmiş constexpr
olarak constexpr
bildirilen ifadelerin artık if ve switch deyimleri, döngü deyimleri ve yaşam süresi ifade değerlendirmesi içinde başlayan nesnelerin mutasyonu gibi belirli bildirim türlerini içermesine constexpr
izin verilir. Artık statik olmayan bir constexpr
üye işlevinin örtük olarak const
olması gerekmez. Daha fazla bilgi için bkz. İşlevler üzerindeki constexpr
kısıtlamaları gevşetme.
C++17: Terse static_assert
için static_assert
ileti parametresi isteğe bağlıdır. Daha fazla bilgi için bkz . N3928: static_assert genişletme, v2.
C++17: [[fallthrough]]
öznitelik
Modunda /std:c++17
ve daha sonraki sürümlerde, özniteliği, [[fallthrough]]
geçiş deyimleri bağlamında derleyiciye, geçiş davranışının amaçlandığına dair bir ipucu olarak kullanılabilir. Bu öznitelik, derleyicinin bu gibi durumlarda uyarı vermesini engeller. Daha fazla bilgi için bkz. P0188R0 - Wording for [[fallthrough]] attribute
.
Genelleştirilmiş aralık tabanlı for
döngüler
Aralık tabanlı for
döngüler artık bunu begin()
gerektirmez ve end()
aynı türdeki nesneleri döndürür. Bu değişiklik, içindeki aralıklar range-v3
tarafından kullanılan bir sentinel ve tamamlanmış ancak tam olarak yayımlanmayan Aralıklar Teknik Belirtimi'nin döndürülmesine olanak tanırend()
. Daha fazla bilgi için bkz. P0184R0 - Generalizing the Range-Based for Loop
.
Kopya listesi-başlatma
Visual Studio 2017, başlatıcı listelerini kullanarak nesne oluşturmayla ilgili derleyici hatalarını doğru şekilde yükseltir. Bu hatalar Visual Studio 2015'te yakalanmadı ve kilitlenmelere veya tanımsız çalışma zamanı davranışına yol açabilir. N4594 13.3.1.7p1
'de copy-list-initialization
olduğu gibi, derleyicinin aşırı yükleme çözümlemesi için açık bir oluşturucuyu göz önünde bulundurması gerekir. Ancak, belirli bir aşırı yükleme seçilirse bir hata oluşturmalıdır.
Aşağıdaki iki örnek Visual Studio 2015'te derlenmiş ancak Visual Studio 2017'de derlenmemektedir.
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 &'
}
Hatayı düzeltmek için doğrudan başlatmayı kullanın:
A a1{ 1 };
const A& a2{ 1 };
Visual Studio 2015'te, derleyici hatalı bir şekilde normal kopya başlatma ile aynı şekilde copy-list-initialization işlemi yaptı: yalnızca aşırı yükleme çözümlemesi için oluşturucuları dönüştürmeyi düşündü. Aşağıdaki örnekte Visual Studio 2015 öğesini seçer MyInt(23)
. Visual Studio 2017 hatayı doğru bir şekilde yükseltir.
// From http://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
}
Bu örnek öncekine benzer ancak farklı bir hata oluşturur. Visual Studio 2015'te başarılı olur ve C2668 ile Visual Studio 2017'de başarısız olur.
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
}
Kullanım dışı tür tanımları
Visual Studio 2017 artık bir sınıfta veya yapıda bildirilen kullanım dışı tür tanımları için doğru uyarıyı verdi. Aşağıdaki örnek, Visual Studio 2015'te uyarı olmadan derlenir. Visual Studio 2017'de C4996 üretir.
struct A
{
// also for __declspec(deprecated)
[[deprecated]] typedef int inttype;
};
int main()
{
A::inttype a = 0; // C4996 'A::inttype': was declared deprecated
}
constexpr
Koşullu değerlendirme işleminin sol tarafındaki işlenen bir bağlamda geçerli constexpr
olmadığında Visual Studio 2017 doğru bir hata oluşturur. Aşağıdaki kod Visual Studio 2015'te derlenmiş ancak C3615'i yükselttiği Visual Studio 2017'de derlenmemektedir:
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
}
Hatayı düzeltmek için işlevini olarak constexpr
bildirin array::size()
veya niteleyiciyi constexpr
'den f
kaldırın.
Sınıf türleri variadic işlevlerine geçirildi
Visual Studio 2017'de, gibi printf
bir variadic işlevine geçirilen sınıflar veya yapılar önemsiz olarak kopyalanabilir olmalıdır. Bu tür nesneler geçirildiğinde, derleyici yalnızca bit düzeyinde bir kopya yapar ve oluşturucuyu veya yıkıcıyı çağırmaz.
#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
}
Hatayı düzeltmek için, önemsiz olarak kopyalanabilir bir tür döndüren bir üye işlevini çağırabilirsiniz.
std::atomic<int> i(0);
printf("%i\n", i.load());
veya geçirmeden önce nesneyi dönüştürmek için statik bir atama kullanın:
struct S {/* as before */} s(0);
printf("%i\n", static_cast<int>(s))
kullanılarak CString
oluşturulan ve yönetilen dizeler için, sağlanan operator LPCTSTR()
bir nesneyi biçim dizesi tarafından beklenen C işaretçisine göndermek CString
için kullanılmalıdır.
CString str1;
CString str2 = _T("hello!");
str1.Format(_T("%s"), static_cast<LPCTSTR>(str2));
Sınıf yapımında Cv-niteleyiciler
Visual Studio 2015'te derleyici bazen oluşturucu çağrısı aracılığıyla bir sınıf nesnesi oluştururken cv-qualifier'ı yanlış bir şekilde yoksayar. Bu sorun kilitlenmeye veya beklenmeyen çalışma zamanı davranışına neden olabilir. Aşağıdaki örnek Visual Studio 2015'te derlenmiş ancak Visual Studio 2017'de derleyici hatası oluşturms:
struct S
{
S(int);
operator int();
};
int i = (const S)0; // error C2440
Hatayı düzeltmek için olarak const
bildirinoperator int()
.
Şablonlardaki nitelenmiş adları denetleme erişimi
Derleyicinin önceki sürümleri bazı şablon bağlamlarında nitelenmiş adlara erişimi denetlemedi. Bu sorun, adın erişilememesi nedeniyle değiştirmenin başarısız olması beklenen SFINAE davranışını etkileyebilir. Derleyici işlecin yanlış aşırı yüklemesini yanlış çağırdığı için çalışma zamanında kilitlenmeye veya beklenmeyen davranışa neden olmuş olabilir. Visual Studio 2017'de bir derleyici hatası oluşur. Belirli bir hata farklılık gösterebilir, ancak tipik bir hata C2672'dir ve "eşleşen aşırı yüklenmiş işlev bulunamadı." Aşağıdaki kod Visual Studio 2015'te derlenmiş ancak Visual Studio 2017'de hataya neden olur:
#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.
}
Şablon bağımsız değişken listeleri eksik
Visual Studio 2015 ve önceki sürümlerinde, derleyici tüm eksik şablon bağımsız değişken listelerini tanılamadı. Eksik şablon bir şablon parametre listesinde göründüğünde not almazsınız: örneğin, varsayılan şablon bağımsız değişkeninin bir parçası veya türü olmayan bir şablon parametresi eksik olduğunda. Bu sorun, derleyici kilitlenmeleri veya beklenmeyen çalışma zamanı davranışı gibi öngörülemeyen davranışlara neden olabilir. Aşağıdaki kod Visual Studio 2015'te derlenmiş ancak Visual Studio 2017'de bir hata oluşturur.
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;
İfade-SFINAE
İfade-SFINAE'yi desteklemek için, derleyici artık şablonlar örneği değil bildirildiğinde bağımsız değişkenleri ayrıştırıyor decltype
. Bu nedenle bağımsız değişkende decltype
bağımlı olmayan bir özelleştirme bulunursa, örnek oluşturma süresine kadar ertelenmiyor. Hemen işlenir ve bu sırada ortaya çıkan hatalar tanılanır.
Aşağıdaki örnekte, bildirim noktasında oluşturulan böyle bir derleyici hatası gösterilmektedir:
#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");
Anonim ad alanında bildirilen sınıflar
C++ standardına göre, anonim ad alanı içinde bildirilen bir sınıfın iç bağlantısı vardır ve bu da dışarı aktarılabildiği anlamına gelir. Visual Studio 2015 ve önceki sürümlerinde bu kural uygulanmadı. Visual Studio 2017'de kural kısmen zorunlu kılındı. Visual Studio 2017'de aşağıdaki örnek C2201 hatasını yükseltir:
struct __declspec(dllexport) S1 { virtual void f() {} };
// C2201 const anonymous namespace::S1::vftable: must have external linkage
// in order to be exported/imported.
Değer sınıfı üyeleri için varsayılan başlatıcılar (C++/CLI)
Visual Studio 2015 ve önceki sürümlerinde, derleyici bir değer sınıfının üyesi için varsayılan üye başlatıcıya izin verdi (ancak yoksayıldı). Bir değer sınıfının varsayılan olarak başlatılması her zaman üyeleri sıfır başlatır. Varsayılan oluşturucuya izin verilmez. Visual Studio 2017'de, varsayılan üye başlatıcılar bu örnekte gösterildiği gibi bir derleyici hatası oluşturur:
value struct V
{
int i = 0; // error C3446: 'V::i': a default member initializer
// isn't allowed for a member of a value class
};
Varsayılan dizin oluşturucular (C++/CLI)
Visual Studio 2015 ve önceki sürümlerinde, derleyici bazı durumlarda varsayılan bir özelliği varsayılan dizin oluşturucu olarak yanlış tanımlamıştı. Özelliğine erişmek için tanımlayıcıyı default
kullanarak soruna geçici bir çözüm bulmak mümkündü. Geçici çözümün kendisi, C++11'de anahtar sözcük olarak tanıtıldıktan sonra default
sorunlu hale geldi. Visual Studio 2017'de geçici çözümü gerektiren hatalar düzeltildi. Derleyici artık bir sınıfın varsayılan özelliğine erişmek için kullanıldığında bir hata default
oluşturur.
//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
}
Visual Studio 2017'de her iki Değer özelliğine de adıyla erişebilirsiniz:
#using "class1.dll"
void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2)
{
r1->Value;
r2->Value;
}
15.3'te uyumluluk iyileştirmeleri
constexpr
Lambda
Lambda ifadeleri artık sabit ifadelerde kullanılabilir. Daha fazla bilgi için bkz. constexpr
C++ dilinde lambda ifadeleri.
if constexpr
işlev şablonlarında
İşlev şablonu, derleme zamanı dallanmayı etkinleştirmek için deyimler içerebilir if constexpr
. Daha fazla bilgi için bkz if constexpr
. deyimler.
Başlatıcılı seçim deyimleri
Deyimi if
, deyiminin içindeki blok kapsamında bir değişken tanıtır bir başlatıcı içerebilir. Daha fazla bilgi için bkz if
. başlatıcılı deyimler.
[[maybe_unused]]
ve [[nodiscard]]
öznitelikleri
Yeni öznitelik [[maybe_unused]]
, bir varlık kullanılmadığında uyarıları sessize alır. özniteliği, [[nodiscard]]
bir işlev çağrısının dönüş değeri atılırsa bir uyarı oluşturur. Daha fazla bilgi için bkz . C++ dilinde öznitelikler.
Yineleme olmadan öznitelik ad alanlarını kullanma
Öznitelik listesinde yalnızca tek bir ad alanı tanımlayıcısını etkinleştirmek için yeni söz dizimi. Daha fazla bilgi için bkz . C++ dilinde öznitelikler.
Yapılandırılmış bağlamalar
Artık tek bir bildirimde, bir değer bir dizi std::tuple
, bir veya olduğunda veya std::pair
tüm genel statik olmayan veri üyelerine sahip olduğunda bileşenlerinin tek tek adlarıyla bir değeri depolamak mümkündür. Daha fazla bilgi için bkz P0144R0 - Structured Bindings
. ve İşlevden birden çok değer döndürme.
Değerler için enum class
inşaat kuralları
Artık daraltmayan kapsamlı sabit listeleri için örtük bir dönüştürme vardır. Kapsamı belirlenmiş bir numaralandırmanın temel türünden numaralandırmanın kendisine dönüştürür. Dönüştürme, tanımı numaralandırıcı eklemediğinde ve kaynak bir liste başlatma söz dizimi kullandığında kullanılabilir. Daha fazla bilgi için bkz P0138R2 - Construction Rules for enum class Values
. ve Numaralandırmalar.
Değere göre yakalama *this
*this
Lambda ifadesindeki nesne artık değere göre yakalanabilir. Bu değişiklik, özellikle daha yeni makine mimarilerinde lambda'nın paralel ve zaman uyumsuz işlemlerde çağrıldığı senaryoları etkinleştirir. Daha fazla bilgi için bkz. P0018R3 - Lambda Capture of *this by Value as [=,*this]
.
Için kaldırılıyor operator++
bool
operator++
artık türlerde bool
desteklenmiyor. Daha fazla bilgi için bkz. P0002R1 - Remove Deprecated operator++(bool)
.
Kullanım dışı anahtar register
sözcüğü kaldırma
Daha register
önce kullanım dışı bırakılan (ve derleyici tarafından yoksayılan) anahtar sözcüğü artık dilden kaldırılmıştır. Daha fazla bilgi için bkz. P0001R1 - Remove Deprecated Use of the register Keyword
.
Silinen üye şablonlarına yapılan çağrılar
Visual Studio'nun önceki sürümlerinde, bazı durumlarda derleyici silinmiş üye şablonuna hatalı biçimlendirilmiş çağrılar için bir hata yaymada başarısız olurdu. Bu çağrılar çalışma zamanında kilitlenmelere neden olabilir. Aşağıdaki kod artık C2280 üretir:
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
}
Hatayı düzeltmek için olarak int
bildirini
.
Tür özellikleri için ön koşul denetimleri
Visual Studio 2017 sürüm 15.3, türün özelliklerine yönelik ön koşul denetimlerini geliştirerek standardı daha katı bir şekilde izler. Böyle bir denetim atanabilir içindir. Aşağıdaki kod Visual Studio 2017 sürüm 15.3'te C2139 üretir:
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
Yerelden yönetilene sıralamada yeni derleyici uyarısı ve çalışma zamanı denetimleri
Yönetilen işlevlerden yerel işlevlere çağrılması için hazırlama gerekir. CLR, sıralamayı yapar, ancak C++ semantiğini anlamaz. Yerel bir nesneyi değere göre geçirirseniz, CLR nesnenin kopya oluşturucusunu çağırır veya kullanır BitBlt
ve bu da çalışma zamanında tanımsız davranışa neden olabilir.
Derleyici şimdi derleme zamanında bu hatayı bulursa bir uyarı yayar: Silinen kopya ctor'a sahip yerel bir nesne değere göre yerel ve yönetilen bir sınır arasında geçirilir. Derleyicinin derleme zamanında bilmediği durumlarda, program hatalı biçimlendirilmiş bir hazırlama gerçekleştiğinde hemen çağıracak std::terminate
şekilde bir çalışma zamanı denetimi ekler. Visual Studio 2017 sürüm 15.3'te aşağıdaki kod C4606 uyarısını oluşturur:
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.`
}
Hatayı düzeltmek için çağıranı #pragma managed
yerel olarak işaretlemek ve sıralamaktan kaçınmak için yönergesini kaldırın.
WinRT için deneysel API uyarısı
Deneme ve geri bildirim için yayımlanan WinRT API'leri ile Windows.Foundation.Metadata.ExperimentalAttribute
dekore edilmiştir. Visual Studio 2017 sürüm 15.3'te, derleyici bu öznitelik için uyarı C4698 üretir. Windows SDK'sının önceki sürümlerindeki birkaç API zaten özniteliğiyle dekore edilmiştir ve bu API'lere yapılan çağrılar artık bu derleyici uyarısını tetikler. Daha yeni Windows SDK'larında özniteliği tüm gönderilen türlerden kaldırılmıştır. Daha eski bir SDK kullanıyorsanız, gönderilen türlere yapılan tüm çağrılar için bu uyarıları gizlemeniz gerekir.
Aşağıdaki kod C4698 uyarısını oluşturur:
Windows::Storage::IApplicationDataStatics2::GetForUserAsync(); // C4698
// 'Windows::Storage::IApplicationDataStatics2::GetForUserAsync' is for
// evaluation purposes only and is subject to change or removal in future updates
Uyarıyı devre dışı bırakmak için bir #pragma ekleyin:
#pragma warning(push)
#pragma warning(disable:4698)
Windows::Storage::IApplicationDataStatics2::GetForUserAsync();
#pragma warning(pop)
Şablon üye işlevinin satır dışı tanımı
Visual Studio 2017 sürüm 15.3, sınıfında bildirlmamış bir şablon üyesi işlevinin satır dışı tanımı için bir hata oluşturur. Aşağıdaki kod artık C2039 hatasını üretir:
struct S {};
template <typename T>
void S::f(T t) {} // C2039: 'f': is not a member of 'S'
Hatayı düzeltmek için sınıfına bir bildirim ekleyin:
struct S {
template <typename T>
void f(T t);
};
template <typename T>
void S::f(T t) {}
İşaretçinin adresini this
almaya çalışma
C++'da, this
X işaretçisi türünde bir prvalue değeridir. adresini this
alamaz veya bir lvalue başvurusuna bağlayamazsınız. Visual Studio'nun önceki sürümlerinde, derleyici bir atama kullanarak bu kısıtlamayı aşmanıza izin verecekti. Visual Studio 2017 sürüm 15.3'te derleyici C2664 hatası üretir.
Erişilemeyen bir temel sınıfa dönüştürme
Visual Studio 2017 sürüm 15.3, bir türü erişilemeyen bir temel sınıfa dönüştürmeye çalıştığınızda bir hata üretir. Aşağıdaki kod kötü biçimlendirilmiş ve çalışma zamanında kilitlenmeye neden olabilir. Derleyici artık aşağıdaki gibi bir kod gördüğünde C2243 üretir:
#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());
}
Üye işlevlerin satır dışı tanımlarında varsayılan bağımsız değişkenlere izin verilmez
Şablon sınıflarındaki üye işlevlerin satır dışı tanımlarında varsayılan bağımsız değişkenlere izin verilmez. Derleyici altında bir uyarı ve altında /permissive
/permissive-
sabit bir hata verecek.
Visual Studio'nun önceki sürümlerinde aşağıdaki kötü biçimlendirilmiş kod çalışma zamanı kilitlenmesine neden olabilir. Visual Studio 2017 sürüm 15.3 uyarı C5037 üretir:
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
{
// ...
}
Hatayı düzeltmek için varsayılan bağımsız değişkeni kaldırın = false
.
offsetof
Bileşik üye göstergesi ile kullanımı
Visual Studio 2017 sürüm 15.3'te, offsetof(T, m)
m bir "bileşik üye belirleyicisi" olduğunda seçeneğiyle derleme yaptığınızda uyarıyla /Wall
sonuçlanır. Aşağıdaki kod kötü biçimlendirilmiş ve çalışma zamanında kilitlenmeye neden olabilir. Visual Studio 2017 sürüm 15.3 uyarı C4841 üretir:
struct A {
int arr[10];
};
// warning C4841: non-standard extension used: compound member designator used in offsetof
constexpr auto off = offsetof(A, arr[2]);
Kodu düzeltmek için uyarıyı bir pragma ile devre dışı bırakın veya kodu kullanmamak offsetof
için değiştirin:
#pragma warning(push)
#pragma warning(disable: 4841)
constexpr auto off = offsetof(A, arr[2]);
#pragma warning(pop)
Statik veri üyesi veya üye işleviyle kullanma offsetof
Visual Studio 2017 sürüm 15.3'te, offsetof(T, m)
m'nin statik veri üyesine veya üye işlevine başvurduğu durumlarda hataya neden olur. Aşağıdaki kod C4597 hatasını oluşturur:
#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'
Bu kod kötü biçimlendirilmiş ve çalışma zamanında kilitlenmeye neden olabilir. Hatayı düzeltmek için kodu tanımlanmamış davranışı artık çağıracak şekilde değiştirin. C++ standardı tarafından izin verilmeyen taşınabilir olmayan kod.
Özniteliklerde __declspec
yeni uyarı
Visual Studio 2017 sürüm 15.3'te, bağlantı belirtimi öncesinde extern "C"
uygulandığında __declspec(...)
derleyici artık öznitelikleri yoksaymamaktadır. Daha önce derleyici, çalışma zamanı etkileri olabilecek özniteliği yoksayacaktı. /Wall
ve /WX
seçenekleri ayarlandığında, aşağıdaki kod C4768 uyarısını üretir:
__declspec(noinline) extern "C" HRESULT __stdcall // C4768: __declspec attributes before linkage specification are ignored
Uyarıyı düzeltmek için önce şunu koyun extern "C"
:
extern "C" __declspec(noinline) HRESULT __stdcall
Visual Studio 2017 sürüm 15.3'te bu uyarı varsayılan olarak kapalıdır ve yalnızca ile /Wall
/WX
derlenen kodu etkiler. Visual Studio 2017 sürüm 15.5'den başlayarak, varsayılan olarak düzey 3 uyarısı olarak etkinleştirilir.
decltype
ve silinen yıkıcılara yapılan çağrılar
Visual Studio'nun önceki sürümlerinde derleyici, ile decltype
ilişkilendirilmiş ifade bağlamında silinmiş bir yıkıcıya yapılan çağrının ne zaman oluştuğuna ilişkin bir algılama yapmamıştı. Visual Studio 2017 sürüm 15.3'te aşağıdaki kod C2280 hatasını oluşturur:
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
}
Başlatılmamış const değişkenleri
Visual Studio 2017 RTW sürümünde regresyon vardı: C++ derleyicisi başlatılmamış const
bir değişken için tanılama oluşturmaz. Bu regresyon Visual Studio 2017 sürüm 15.3'te düzeltilmiştir. Aşağıdaki kod artık C4132 uyarısını üretir:
const int Value; // C4132: 'Value': const object should be initialized
Hatayı düzeltmek için öğesine bir değer atayın Value
.
Boş bildirimler
Visual Studio 2017 sürüm 15.3 artık yalnızca yerleşik türler için değil, tüm türler için boş bildirimler konusunda uyarır. Aşağıdaki kod artık dört bildirimin tümü için düzey 2 C4091 uyarısı oluşturur:
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
Uyarıları kaldırmak için açıklamayı çıkarın veya boş bildirimleri kaldırın. Adsız nesnenin yan etkisine (RAII gibi) sahip olması amaçlandığı durumlarda, nesneye bir ad verilmelidir.
Uyarı, W2 uyarı düzeyi altında /Wv:18
dışlanır ve varsayılan olarak açıktır.
std::is_convertible
dizi türleri için
Derleyicinin önceki sürümleri dizi türleri için std::is_convertible
yanlış sonuçlar verdi. Bu, tür özelliğini kullanırken std::is_convertible<...>
Microsoft C++ derleyicisi için özel durumda kitaplık yazarları gerektirir. Aşağıdaki örnekte, statik onaylar Visual Studio'nun önceki sürümlerini geçirir ancak Visual Studio 2017 sürüm 15.3'te başarısız olur:
#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>
sanal işlev tanımının iyi biçimlendirilmiş olup olmadığını denetleyerek hesaplanır:
To test() { return std::declval<From>(); }
Özel yıkıcılar ve std::is_constructible
Derleyicinin önceki sürümleri, sonucuna std::is_constructible
karar verirken bir yıkıcının özel olup olmadığını yoksayıyordu. Şimdi onları dikkate alır. Aşağıdaki örnekte, statik onaylar Visual Studio'nun önceki sürümlerini geçirir ancak Visual Studio 2017 sürüm 15.3'te başarısız olur:
#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);
Özel yıkıcılar bir türün oluşturulamaz olmasına neden olur. std::is_constructible<T, Args...>
, aşağıdaki bildirimin yazıldığı gibi hesaplanır:
T obj(std::declval<Args>()...)
Bu çağrı bir yıkıcı çağrısı anlamına gelir.
C2668: Belirsiz aşırı yükleme çözünürlüğü
Derleyicinin önceki sürümleri bazen hem bildirimler hem de bağımsız değişkene bağımlı arama kullanarak birden çok aday bulduğunda belirsizliği algılayamadı. Bu hata yanlış aşırı yüklemenin seçilmesine ve beklenmeyen çalışma zamanı davranışına neden olabilir. Aşağıdaki örnekte, Visual Studio 2017 sürüm 15.3 C2668'i doğru şekilde yükseltir:
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
}
Kodu düzeltmek için çağrısı ::f()
yapmak istiyorsanız using N::f
deyimini kaldırın.
C2660: yerel işlev bildirimleri ve bağımsız değişkene bağlı arama
Yerel işlev bildirimleri, kapsayan kapsamda işlev bildirimini gizler ve bağımsız değişkene bağımlı aramayı devre dışı bırakır. Derleyicinin önceki sürümleri bu durumda her zaman bağımsız değişkene bağımlı arama yapmıştır. Derleyici yanlış aşırı yüklemeyi seçtiyse beklenmeyen çalışma zamanı davranışına yol açabilir. Genellikle hatanın nedeni yerel işlev bildiriminin yanlış imzasıdır. Aşağıdaki örnekte, Visual Studio 2017 sürüm 15.3 C2660'ı doğru şekilde yükseltir:
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);
}
Sorunu düzeltmek için imzayı f(S)
değiştirin veya kaldırın.
C5038: başlatıcı listelerinde başlatma sırası
Sınıf üyeleri, başlatıcı listelerinde göründükleri sırayla değil, bildirildikleri sırayla başlatılır. Derleyicinin önceki sürümleri, başlatıcı listesinin sırası bildirim sırasından farklı olduğunda uyarmadı. Bir üyenin başlatılması zaten başlatılmakta olan listedeki başka bir üyeye bağlıysa, bu sorun tanımlanmamış çalışma zamanı davranışına yol açabilir. Aşağıdaki örnekte, Visual Studio 2017 sürüm 15.3 (ile/Wall
) C5038 uyarısını oluşturur:
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;
};
Sorunu düzeltmek için başlatıcı listesini bildirimlerle aynı sıraya sahip olacak şekilde düzenleyin. Başlatıcılardan biri veya her ikisi de temel sınıf üyelerine başvurduğunda benzer bir uyarı oluşturulur.
Bu uyarı varsayılan olarak kapalıdır ve yalnızca ile /Wall
derlenen kodu etkiler.
15.5'te uyumluluk iyileştirmeleri
[14] ile işaretlenmiş özellikler, modda bile /std:c++14
koşulsuz olarak kullanılabilir.
için yeni derleyici anahtarı extern constexpr
Visual Studio'nun önceki sürümlerinde, değişkeni işaretlendiğinde extern
bile derleyici her zaman bir constexpr
değişken iç bağlantı verdi. Visual Studio 2017 sürüm 15.5'te, yeni bir derleyici anahtarı, /Zc:externConstexpr
doğru ve standartlara uygun davranışı etkinleştirir. Daha fazla bilgi için bkz extern constexpr
. bağlantı.
Dinamik özel durum belirtimleri kaldırılıyor
P0003R5 Dinamik özel durum belirtimleri C++11'de kullanım dışı bırakıldı. Özellik C++17'den kaldırılır, ancak (yine de) kullanım dışı belirtimi throw()
kesinlikle için noexcept(true)
bir diğer ad olarak tutulur. Daha fazla bilgi için bkz . Dinamik özel durum belirtimi kaldırma ve noexcept
.
not_fn()
not_fn
P0005R4 ve not2
öğesinin not1
yerine geçer.
Yeniden oluşturma enable_shared_from_this
enable_shared_from_this
P0033R1 C++11'e eklendi. C++17 standardı, belirli köşe durumlarını daha iyi işlemek için belirtimi güncelleştirir. [14]
Haritaları ve kümeleri ekleme
P0083R3 Bu özellik, unordered_map
map
set
daha sonra değiştirilebilen ve aynı kapsayıcıya veya aynı düğüm türünü kullanan farklı bir kapsayıcıya eklenebilen ilişkilendirilebilir kapsayıcılardan (, , unordered_set
) düğümlerin ayıklanmasına olanak tanır. (Yaygın bir kullanım örneği, bir std::map
düğümü içinden ayıklamak, anahtarı değiştirmek ve yeniden eklemektir.)
Vestigial kitaplık bölümlerini kullanımdan kaldırma
P0174R2 C++ standart kitaplığının çeşitli özellikleri yıllar içinde daha yeni özelliklerle değiştirildi, aksi halde yararlı veya sorunlu bulunmadı. Bu özellikler C++17'de resmi olarak kullanım dışı bırakılmıştır.
içinde ayırıcı desteği kaldırılıyor std::function
P0302R1 C++17'den önce, sınıf şablonunun std::function
ayırıcı bağımsız değişkenini alan çeşitli oluşturucuları vardı. Ancak bu bağlamda ayırıcıların kullanımı sorunluydu ve semantik belirsizdi. Sorun contructors kaldırıldı.
Için düzeltmeler not_fn()
P0358R1 Için std::not_fn
yeni ifade, sarmalayıcı çağırmada kullanıldığında değer kategorisinin yayılmasını destekler.
shared_ptr<T[]>
, shared_ptr<T[N]>
P0414R2 Kitaplık Temelleri'nden C++17'ye değişiklikleri birleştirmeshared_ptr
. [14]
Diziler için düzeltme shared_ptr
P0497R0 Diziler için shared_ptr desteğine yönelik düzeltmeler. [14]
Netleştirme insert_return_type
P0508R0 Benzersiz anahtarlarla ilişkilendirilen kapsayıcılar ve benzersiz anahtarlara sahip sıralanmamış kapsayıcıların iç içe türü insert_return_type
döndüren bir üye işlevi insert
vardır. Bu dönüş türü artık kapsayıcının Yineleyicisi ve NodeType'larında parametreleştirilmiş bir türün özelleştirmesi olarak tanımlanır.
Standart kitaplık için satır içi değişkenler
P0607R0 için, standart kitaplıkta bildirilen birkaç ortak değişken artık satır içinde bildirilir.
Ek D özellikleri kullanım dışı
C++ standardının Ek D'si, , <codecvt>
ve namespace std::tr1
dahil olmak üzere shared_ptr::unique()
kullanım dışı bırakılan tüm özellikleri içerir. /std:c++17
Veya sonraki derleyici seçeneği ayarlandığında, Ek D'deki neredeyse tüm standart kitaplık özellikleri kullanım dışı olarak işaretlenir. Daha fazla bilgi için bkz . Ek D'deki Standart kitaplık özellikleri kullanım dışı olarak işaretlenir.
içindeki std::tr2::sys
<experimental/filesystem>
ad alanı artık altında varsayılan olarak bir kullanımdan kaldırma uyarısı /std:c++14
yayar ve artık varsayılan olarak ve altında /std:c++17
kaldırılmıştır.
Standart olmayan bir uzantıdan (sınıf içi açık özelleştirmeler) kaçınarak 'de uyumluluğu <iostream>
iyileştirildi.
Standart kitaplık artık değişken şablonlarını dahili olarak kullanıyor.
Standart kitaplık C++17 derleyici değişikliklerine yanıt olarak güncelleştirildi. Güncelleştirmeler, tür sistemine eklenmesini noexcept
ve dynamic-exception-specifications'ın kaldırılmasını içerir.
Kısmi sıralama değişikliği
Derleyici şimdi aşağıdaki kodu doğru şekilde reddeder ve doğru hata iletisini verir:
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*)'
Yukarıdaki örnekteki sorun, türlerde iki fark olmasıdır (const ile const-non-const ve pack-non-pack). Derleyici hatasını ortadan kaldırmak için farklardan birini kaldırın. Daha sonra derleyici, işlevleri kesin olarak sıralayabilir.
template<typename... T>
int f(T* ...)
{
return 1;
}
template<typename T>
int f(T&)
{
return 2;
}
int main()
{
int i = 0;
f(&i);
}
Özel durum işleyicileri
Dizi veya işlev türüne başvuru işleyicileri hiçbir özel durum nesnesiyle eşleşmez. Derleyici artık bu kuralı doğru şekilde yerine getirir ve C4843 düzey 4 uyarısını yükseltir. Ayrıca kullanıldığında artık veya wchar_t*
işleyicisi char*
ile dize değişmez değeri /Zc:strictStrings
eşleşmez.
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şağıdaki kod hatadan kaçınıyor:
catch (int (*)[1]) {}
std::tr1
ad alanı kullanım dışı bırakıldı
Standart std::tr1
olmayan ad alanı artık hem C++14 hem de C++17 modlarında kullanım dışı olarak işaretlenir. Visual Studio 2017 sürüm 15.5'te aşağıdaki kod C4996'yı oluşturur:
#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.
Hatayı düzeltmek için ad alanına başvuruyu tr1
kaldırın:
#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;
}
Ek D'deki standart kitaplık özellikleri kullanım dışı olarak işaretlenir
/std:c++17
Mod veya sonraki derleyici anahtarı ayarlandığında, Ek D'deki neredeyse tüm standart kitaplık özellikleri kullanım dışı olarak işaretlenir.
Visual Studio 2017 sürüm 15.5'te aşağıdaki kod C4996'yı oluşturur:
#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.
Hatayı düzeltmek için aşağıdaki kodda gösterildiği gibi uyarı metnindeki yönergeleri izleyin:
#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");
Başvurulmayan yerel değişkenler
Visual Studio 15.5'te, aşağıdaki kodda gösterildiği gibi C4189 uyarısı daha fazla durumda yayılır:
void f() {
char s[2] = {0}; // C4189. Either use the variable or remove it.
}
warning C4189: 's': local variable is initialized but not referenced
Hatayı düzeltmek için kullanılmayan değişkeni kaldırın.
Tek satırlı açıklamalar
Visual Studio 2017 sürüm 15.5'te, C4001 ve C4179 uyarıları artık C derleyicisi tarafından belirtilmez. Daha önce, yalnızca derleyici anahtarı altında /Za
gösterildiler. Tek satırlı açıklamalar C99'dan bu yana C standardının bir parçası olduğundan artık uyarılar gerekli değildir.
/* 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'
Kodun geriye dönük uyumlu olması gerekmediğinde, C4001 ve C4179 gizlemesini kaldırarak uyarıdan kaçının. Kodun geriye dönük olarak uyumlu olması gerekiyorsa yalnızca C4619'un gizlenmesi gerekir.
/* C only */
#pragma warning(disable:4619)
#pragma warning(disable:4001)
#pragma warning(disable:4179)
// single line comment
/* single line comment */
__declspec
bağlantı içeren extern "C"
öznitelikler
Visual Studio'nun önceki sürümlerinde, bağlama belirtiminin öncesinde extern "C"
uygulandığında __declspec(...)
derleyici öznitelikleri yoksayıyordu__declspec(...)
. Bu davranış, kullanıcının amaçlamamasına neden olan kodun oluşturulmasına ve olası çalışma zamanı etkilerine neden oldu. C4768 uyarısı Visual Studio sürüm 15.3'e eklendi, ancak varsayılan olarak kapalıydı. Visual Studio 2017 sürüm 15.5'te uyarı varsayılan olarak etkindir.
__declspec(noinline) extern "C" HRESULT __stdcall // C4768
warning C4768: __declspec attributes before linkage specification are ignored
Hatayı düzeltmek için bağlantı belirtimini __declspec özniteliğinden önce yerleştirin:
extern "C" __declspec(noinline) HRESULT __stdcall
Bu yeni uyarı C4768, Visual Studio 2017 15.3 veya daha eski sürümlerle gönderilen bazı Windows SDK üst bilgilerinde (örneğin: RS2 SDK olarak da bilinen sürüm 10.0.15063.0) verilir. Ancak Windows SDK üst bilgilerinin sonraki sürümleri (özellikle ShlObj.h ve ShlObj_core.h) uyarıyı üretmemeleri için düzeltilmiştir. Windows SDK üst bilgilerinden gelen bu uyarıyı gördüğünüzde şu eylemleri gerçekleştirebilirsiniz:
Visual Studio 2017 sürüm 15.5 sürümüyle birlikte gelen en son Windows SDK'sına geçin.
Windows SDK üst bilgi deyiminin #include uyarısını kapatın:
#pragma warning (push)
#pragma warning(disable:4768)
#include <shlobj.h>
#pragma warning (pop)
extern constexpr
Bağlantı
Visual Studio'nun önceki sürümlerinde, değişkeni işaretlendiğinde extern
bile derleyici her zaman bir constexpr
değişken iç bağlantı verdi. Visual Studio 2017 sürüm 15.5'te, yeni bir derleyici anahtarı (/Zc:externConstexpr
) doğru, standartlara uygun davranışı etkinleştirir. Sonunda bu davranış varsayılan olur.
extern constexpr int x = 10;
error LNK2005: "int const x" already defined
Üst bilgi dosyası bildirilen extern constexpr
bir değişken içeriyorsa, yinelenen bildirimlerinin doğru bir şekilde birleştirilmesi için işaretlenmesi __declspec(selectany)
gerekir:
extern constexpr __declspec(selectany) int x = 10;
typeid
tamamlanmamış sınıf türünde kullanılamaz
Visual Studio'nun önceki sürümlerinde, derleyici yanlış bir şekilde aşağıdaki koda izin verdi ve bu da olası yanlış tür bilgilerine neden oldu. Visual Studio 2017 sürüm 15.5'te derleyici doğru bir hata oluşturur:
#include <typeinfo>
struct S;
void f() { typeid(S); } //C2027 in 15.5
error C2027: use of undefined type 'S'
std::is_convertible
hedef türü
std::is_convertible
hedef türün geçerli bir dönüş türü olmasını gerektirir. Visual Studio'nun önceki sürümlerinde, derleyici yanlış şekilde soyut türlere izin verdi ve bu da yanlış aşırı yükleme çözümlemesine ve istenmeyen çalışma zamanı davranışına yol açabilir. Aşağıdaki kod artık C2338'i doğru şekilde yükseltir:
#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
Hatadan kaçınmak için, is_convertible
kullanırken işaretçi türlerini karşılaştırmanız gerekir çünkü bir tür soyut olduğunda işaretçi türü olmayan bir karşılaştırma başarısız olabilir:
#include <type_traits>
struct B { virtual ~B() = 0; };
struct D : public B { virtual ~D(); };
static_assert(std::is_convertible<D *, B *>::value, "fail");
Dinamik özel durum belirtimi kaldırma ve noexcept
C++17'de, throw()
için noexcept
throw(<type list>)
bir diğer addır ve throw(...)
kaldırılır ve bazı türler içerebilirnoexcept
. Bu değişiklik, C++14 veya önceki sürümlere uygun kodda kaynak uyumluluk sorunlarına neden olabilir. Anahtar /Zc:noexceptTypes-
, genel olarak C++17 modu kullanılırken C++14 sürümüne noexcept
geri dönmek için kullanılabilir. Tüm kodunuzu aynı anda yeniden yazmak zorunda kalmadan kaynak kodunuzu C++17'ye uyacak şekilde güncelleştirmenizi throw()
sağlar.
Derleyici artık C++17 modundaki bildirimlerde veya yeni C5043 uyarısıyla /permissive-
daha uyumsuz özel durum belirtimlerini tanılar.
Aşağıdaki kod, geçiş uygulandığında Visual Studio 2017 sürüm 15.5'te C5043 ve C5040 /std:c++17
oluşturur:
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
};
kullanmaya /std:c++17
devam ederken hataları kaldırmak için anahtarı komut satırına ekleyin /Zc:noexceptTypes-
veya aşağıdaki örnekte gösterildiği gibi kodunuzu kullanacak noexcept
şekilde güncelleştirin:
void f() noexcept;
void f() noexcept { }
void g() noexcept(false);
struct A {
virtual void f() noexcept;
};
struct B : A {
virtual void f() noexcept { }
};
Satır içi değişkenler
Statik constexpr
veri üyeleri artık örtük olarak inline
kullanılır. Bu, bir sınıf içindeki bildirimlerinin artık tanımları olduğu anlamına gelir. Veri üyesi için static constexpr
satır dışı bir tanım kullanmak artık gereksizdir ve artık kullanım dışıdır. Visual Studio 2017 sürüm 15.5'te, anahtar uygulandığında /std:c++17
aşağıdaki kod artık C5041 uyarısını üretir:
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(...)
uyarı C4768 artık varsayılan olarak açık
Uyarı Visual Studio 2017 sürüm 15.3'e eklendi, ancak varsayılan olarak kapalıydı. Visual Studio 2017 sürüm 15.5'te uyarı varsayılan olarak açıktır. Daha fazla bilgi için bkz. Özniteliklerle ilgili __declspec
yeni uyarı.
Varsayılan işlevler ve __declspec(nothrow)
Derleyici daha önce, karşılık gelen temel/üye işlevleri özel durumlara izin verildiğinde varsayılan işlevlerin bildirilmesine __declspec(nothrow)
izin verdi. Bu davranış C++ standardına aykırıdır ve çalışma zamanında tanımsız davranışa neden olabilir. Standart, özel durum belirtimi uyuşmazlığı varsa bu tür işlevlerin silinmiş olarak tanımlanmasını gerektirir. altında /std:c++17
, aşağıdaki kod C2280'i yükseltir:
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.
}
Bu kodu düzeltmek için, varsayılan işlevden __declspec(nothrow) kaldırın veya gerekli özel durum işlemeyle birlikte işlev için bir tanım kaldırın = default
ve sağlayın:
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
ve kısmi uzmanlıklar
noexcept
Tür sisteminde, belirli "çağrılabilir" türlerle eşleşen kısmi özelleştirmeler derlenmeyebilir veya işaretçiler-noexcept-functions için eksik kısmi özelleştirme nedeniyle birincil şablonu seçemeyebilir.
Böyle durumlarda, üye işlevlerine yönelik işlev işaretçilerini ve noexcept
işaretçilerini işlemek noexcept
için daha fazla kısmi özelleştirme eklemeniz gerekebilir. Bu aşırı yüklemeler yalnızca modda veya daha sonraki sürümlerde /std:c++17
yasaldır. C++14 ile geriye dönük uyumluluğun korunması gerekiyorsa ve başkalarının tükettiği kodu yazıyorsanız, yönergelerin içinde #ifdef
bu yeni aşırı yüklemeleri korumanız gerekir. Bağımsız bir modülde çalışıyorsanız, korumaları kullanmak #ifdef
yerine yalnızca anahtarla /Zc:noexceptTypes-
derleyebilirsiniz.
Aşağıdaki kod C2027 /std:c++14
hatası altında derlenerek başarısız /std:c++17
olur:
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>'
}
Derleyici yeni kısmi özelleştirmeyi seçtiğinden aşağıdaki kod altında /std:c++17
başarılı olur A<void (*)() noexcept>
:
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
}
15.6'da uyumluluk iyileştirmeleri
C++17 Kitaplık Temelleri V1
P0220R1, C++17 için Kitaplık Temelleri Teknik Belirtimini standarda dahil eder. , , <experimental/optional>
, , <experimental/functional>
, <experimental/any>
, <experimental/string_view>
, <experimental/memory>
<experimental/memory_resource>
ve <experimental/algorithm>
güncelleştirmelerini <experimental/tuple>
kapsar.
C++17: Standart kitaplık için sınıf şablonu bağımsız değişken kesintisini iyileştirme
P0739R0 için parametre listesinin scoped_lock
önüne taşı adopt_lock_t
seçeneğinin tutarlı kullanımını scoped_lock
etkinleştirin. Kopya atamasını etkinleştirmek için oluşturucuya daha fazla durumda aşırı yükleme çözümlemesine katılmasına izin verin std::variant
.
15.7'de uyumluluk iyileştirmeleri
C++17: Devralan oluşturucuları yeniden oluşturma
P0136R1, bir oluşturucuyu adlandıran bir using
bildirimin, daha fazla türetilmiş sınıf oluşturucuları bildirmek yerine, karşılık gelen temel sınıf oluşturucularını türetilmiş sınıfın başlatmalarına görünür hale getirdiğini belirtir. Bu yeniden ifade, C++14 ile yapılan bir değişikliktir. Visual Studio 2017 sürüm 15.7 ve sonraki sürümlerde /std:c++17
, mod ve sonraki sürümlerde, C++14'te geçerli olan ve devralan oluşturucuları kullanan kod geçerli olmayabilir veya farklı semantiklere sahip olabilir.
Aşağıdaki örnekte C++14 davranışı gösterilmektedir:
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).
Aşağıdaki örnekte Visual Studio 15.7'deki davranış gösterilmektedir /std:c++17
:
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)
Daha fazla bilgi için bkz . Oluşturucular.
C++17: Genişletilmiş toplama başlatma
Temel sınıfın oluşturucusu ortak değilse ancak türetilmiş bir sınıf için erişilebilirse, Visual Studio 2017 sürüm 15.7'de modun altında /std:c++17
ve sonrasında türetilmiş türde bir nesneyi başlatmak için artık boş küme ayraçları kullanamazsınız.
Aşağıdaki örnekte C++14 uyumlu davranış gösterilmektedir:
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.
C++17'de artık Derived
toplama türü olarak kabul edilir. Bu, özel varsayılan oluşturucu aracılığıyla başlatma Base
işleminin, genişletilmiş toplama başlatma kuralının bir parçası olarak doğrudan gerçekleştiği anlamına gelir. Daha önce, Base
özel oluşturucu oluşturucu aracılığıyla Derived
çağrıldı ve arkadaş bildirimi nedeniyle başarılı oldu.
Aşağıdaki örnekte, modda Visual Studio sürüm 15.7'de /std:c++17
C++17 davranışı gösterilmektedir:
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: Türü olmayan şablon parametrelerini otomatik olarak bildirme
Modunda /std:c++17
, derleyici artık ile auto
bildirilen tür olmayan bir şablon bağımsız değişkeninin türünü çözebilir:
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
Bu yeni özelliğin bir etkisi, geçerli C++14 kodunun geçerli olmaması veya farklı semantiklere sahip olmasıdır. Örneğin, daha önce geçersiz olan bazı aşırı yüklemeler artık geçerlidir. Aşağıdaki örnekte, çağrısı example(p)
öğesine bağlı example(void*);
olduğundan derlenen C++14 kodu gösterilmektedir. Visual Studio 2017 sürüm 15.7'de /std:c++17
, example
işlev şablonu en iyi eşleşmedir.
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
}
Aşağıdaki örnekte Visual Studio 15.7 modunda C++17 /std:c++17
kodu gösterilmektedir:
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: Temel dize dönüştürmeleri (kısmi)
P0067R5 Tamsayılar ve dizeler arasında ve kayan noktalı sayılar ile dizeler arasında dönüştürmeler için düşük düzeyli, yerel ayardan bağımsız işlevler.
C++20: Gereksiz çürümeyi önleme (kısmi)
P0777R1 "bozulma" kavramı ile yalnızca sabit veya başvuru niteleyicilerini kaldırma kavramı arasında ayrım ekler. Yeni tür özelliği remove_reference_t
bazı bağlamlarda decay_t
yerini alır. desteği remove_cvref_t
Visual Studio 2019'da uygulanır.
C++17: Paralel algoritmalar
P0024R2 Paralellik TS, küçük değişikliklerle standarda dahil edilir.
C++17: hypot(x, y, z)
P0030R1 , ve türleri float
double
için üç yeni aşırı yükleme std::hypot
ekler ve long double
bunların her biri üç giriş parametresine sahiptir.
C++17: <filesystem>
P0218R1 Birkaç sözcük değişikliğiyle Dosya Sistemi TS'sini standarda benimser.
C++17: Matematiksel özel işlevler
P0226R1 Matematiksel Özel İşlevler için önceki teknik belirtimleri standart <cmath>
üst bilgide benimser.
C++17: Standart kitaplık için kesinti kılavuzları
sınıf şablonu bağımsız değişken kesintisi için destek ekleyen P0091R3 C++17'nin benimsenmesinden yararlanmak için STL güncelleştirmelerini P0433R2.
C++17: Temel dize dönüştürmelerini onarma
P0682R1 Yeni temel dize dönüştürme işlevlerini P0067R5 yeni bir üst bilgiye <charconv>
taşıyın ve yerine kullanılacak std::errc
std::error_code
hata işlemeyi değiştirme de dahil olmak üzere başka geliştirmeler yapın.
C++17: constexpr
için char_traits
(kısmi)
sabit ifadelerde kullanılabilir hale getirmek std::string_view
için std::traits_type
, compare
ve find
üye işlevlerinde length
yapılan değişiklikleri P0426R1. (Visual Studio 2017 sürüm 15.6'da, yalnızca Clang/LLVM için desteklenir. Sürüm 15.7'de ClXX için de destek neredeyse tamamlanır.)
C++17: Birincil sınıf şablonunda varsayılan bağımsız değişken
Bu davranış değişikliği için P0091R3 - Template argument deduction for class templates
bir önkoşuldur.
Daha önce, derleyici birincil sınıf şablonundaki varsayılan bağımsız değişkeni yoksaydı:
template<typename T>
struct S {
void f(int = 0);
};
template<typename T>
void S<T>::f(int = 0) {} // Re-definition necessary
/std:c++17
Visual Studio 2017 sürüm 15.7'deki modda varsayılan bağımsız değişken yoksayılamaz:
template<typename T>
struct S {
void f(int = 0);
};
template<typename T>
void S<T>::f(int) {} // Default argument is used
Bağımlı ad çözümlemesi
Bu davranış değişikliği için P0091R3 - Template argument deduction for class templates
bir önkoşuldur.
Aşağıdaki örnekte, Visual Studio 15.6 ve önceki sürümlerindeki derleyici birincil sınıf şablonunda olarak B<T>::type
çözümlenmiştirD::type
.
template<typename T>
struct B {
using type = T;
};
template<typename T>
struct D : B<T*> {
using type = B<T*>::type;
};
Visual Studio 2017 sürüm 15.7, /std:c++17
modunda D deyiminde using
anahtar sözcüğü gerektirirtypename
. olmadan typename
derleyici C4346: 'B<T*>::type': dependent name is not a type
uyarısını ve C2061 hatasını tetikler: : 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]]
öznitelik - uyarı düzeyi artışı
Visual Studio 2017 sürüm 15.7 modunda/std:c++17
, C4834 uyarı düzeyi W3'ten W1'e yükseltilir. uyarısını için bir atama ile veya derleyiciye void
geçirerek /wd:4834
devre dışı bırakabilirsiniz.
[[nodiscard]] int f() { return 0; }
int main() {
f(); // warning C4834: discarding return value
// of function with 'nodiscard'
}
Variadic şablon oluşturucu temel sınıf başlatma listesi
Visual Studio'nun önceki sürümlerinde, şablon bağımsız değişkenleri eksik olan variadic şablon oluşturucu temel sınıf başlatma listesi hatalı bir şekilde hatasız olarak izin veriliyordu. Visual Studio 2017 sürüm 15.7'de derleyici hatası oluşur.
Visual Studio 2017 sürüm 15.7'deki aşağıdaki kod örneği C2614 hatasını oluşturur:
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;
Hatayı düzeltmek için ifadesini olarak B<T>()
değiştirinB()
.
constexpr
toplu başlatma
C++ derleyicisinin önceki sürümleri toplu başlatmayı yanlış işledi constexpr
. Derleyici, aggregate-init-list öğesinin çok fazla öğe içerdiği geçersiz kodu kabul etti ve bunun için hatalı nesne kodu üretti. Aşağıdaki kod, bu tür bir kod örneğidir:
#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;
}
Visual Studio 2017 sürüm 15.7 güncelleştirme 3 ve sonraki sürümlerde, önceki örnek artık C2078'i yükseltmektedir. Aşağıdaki örnekte kodun nasıl düzeltileceğini gösterilmektedir. İç içe küme ayracı-init-lists ile bir std::array
başlatırken, iç diziye kendi küme ayracı listesini verin:
#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;
}
15.8'de uyumluluk iyileştirmeleri
typename
nitelenmemiş tanımlayıcılarda
Modda /permissive-
, diğer ad şablonu tanımlarındaki nitelenmemiş tanımlayıcılardaki sahte typename
anahtar sözcükler artık derleyici tarafından kabul edilmemektedir. Aşağıdaki kod artık C7511 üretir:
template <typename T>
using X = typename T; // C7511: 'T': 'typename' keyword must be
// followed by a qualified name
Hatayı düzeltmek için ikinci satırı olarak using X = T;
değiştirin.
__declspec()
diğer ad şablonu tanımlarının sağ tarafında
__declspec
artık diğer ad şablonu tanımının sağ tarafında kullanılamaz. Daha önce, derleyici bu kodu kabul etti ancak yoksaydı. Diğer ad kullanıldığında hiçbir zaman kullanımdan kaldırma uyarısına neden olmaz.
Bunun yerine standart C++ özniteliği [[deprecated]]
kullanılabilir ve Visual Studio 2017 sürüm 15.6'da dikkate alınmalıdır. Aşağıdaki kod artık C2760 üretir:
template <typename T>
using X = __declspec(deprecated("msg")) T; // C2760: syntax error:
// unexpected token '__declspec',
// expected 'type specifier'`
Hatayı düzeltmek için aşağıdaki koda değiştirin (diğer ad tanımının '=' öğesinin önüne yerleştirilmiş özniteliğiyle):
template <typename T>
using X [[deprecated("msg")]] = T;
İki aşamalı ad arama tanılaması
İki aşamalı ad araması, şablon gövdelerinde kullanılan bağımlı olmayan adların tanım zamanında şablona görünür olmasını gerektirir. Daha önce, Microsoft C++ derleyicisi örnek oluşturma süresine kadar aranmaması için temelsiz bir ad bırakacaktı. Şimdi, bağımlı olmayan adların şablon gövdesine bağlı olmasını gerektirir.
Bunun bildirim oluşturma yollarından biri, bağımlı temel sınıflarda arama yapmaktır. Daha önce, derleyici bağımlı temel sınıflarda tanımlanan adların kullanılmasına izin verdi. Bunun nedeni, tüm türlerin çözümlendiğinde örnekleme sırasında aranmasıdır. Artık kod bir hata olarak değerlendirilir. Bu gibi durumlarda, örneğin bir işaretçi ekleyerek, temel sınıf türüyle niteleyerek veya başka bir this->
şekilde bağımlı hale getirerek değişkeni örnekleme zamanında aranmaya zorlayabilirsiniz.
Modunda /permissive-
, aşağıdaki kod artık C3861'i yükseltir:
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
}
};
Hatayı düzeltmek için deyimini return
olarak return this->base_value;
değiştirin.
Not
1.70'den önceki Boost.Python kitaplığı sürümlerinde, içinde unwind_type.hpp
şablon iletme bildirimi için MSVC'ye özgü bir geçici çözüm sağlanmıştır. /permissive-
Visual Studio 2017 sürüm 15.8' de başlayan_MSC_VER==1915
mod altında, MSVC derleyicisi bağımsız değişkene bağımlı ad aramasını (ADL) doğru şekilde yapar. Artık diğer derleyicilerle tutarlıdır ve bu geçici çözümün gereksiz şekilde korunmasını sağlar. C3861: 'unwind_type': identifier not found
hatasını önlemek için Boost.Python kitaplığınızı güncelleştirin.
ad alanında iletme bildirimleri ve tanımları std
C++ standardı, kullanıcının ad alanına std
iletme bildirimleri veya tanımları eklemesine izin vermez. Ad alanına veya ad alanı içindeki std
bir ad alanına std
bildirim veya tanım eklemek artık tanımsız davranışla sonuçlanır.
Gelecekte Microsoft, bazı standart kitaplık türlerinin tanımlandığı konumu taşıyacaktır. Bu değişiklik, ad alanına std
iletme bildirimleri ekleyen mevcut kodu bozar. C4643 adlı yeni bir uyarı, bu tür kaynak sorunları belirlemenize yardımcı olur. Uyarı modda /default
etkindir ve varsayılan olarak kapalıdır. veya /WX
ile /Wall
derlenen programları etkiler.
Aşağıdaki kod artık C4643'i yükseltir:
namespace std {
template<typename T> class vector; // C4643: Forward declaring 'vector'
// in namespace std is not permitted
// by the C++ Standard`
}
Hatayı düzeltmek için ileriye doğru bildirim yerine bir yönerge kullanın #include
:
#include <vector>
Kendilerine temsilci seçen oluşturucular
C++ standardı, bir temsilci oluşturucu kendisine temsilci olarak atandığında derleyicinin bir tanılama yayması gerektiğini önerir. ve modlarındaki /std:c++17
/std:c++latest
Microsoft C++ derleyicisi artık C7535'i yükseltir.
Bu hata olmadan, aşağıdaki program derlenir ancak sonsuz bir döngü oluşturur:
class X {
public:
X(int, int);
X(int v) : X(v){} // C7535: 'X::X': delegating constructor calls itself
};
Sonsuz döngüden kaçınmak için farklı bir oluşturucuya temsilci seçin:
class X {
public:
X(int, int);
X(int v) : X(v, 0) {}
};
offsetof
sabit ifadelerle
offsetof
geleneksel olarak gerektiren reinterpret_cast
bir makro kullanılarak uygulanmıştır. Bu kullanım, sabit bir ifade gerektiren bağlamlarda geçersizdir, ancak Microsoft C++ derleyicisi geleneksel olarak buna izin verdi. offsetof
Standart kitaplığın parçası olarak gönderilen makro doğru bir derleyici iç ()__builtin_offsetof
kullanır, ancak birçok kişi kendi offsetof
öğesini tanımlamak için makro numarasını kullanmıştı.
Visual Studio 2017 sürüm 15.8'de derleyici, kodun standart C++ davranışına uymasına yardımcı olmak için bu reinterpret_cast
işleçlerin varsayılan modda görüntülenebileceği alanları kısıtlar. altında /permissive-
, kısıtlamalar daha da katıdır. Sabit ifadeler gerektiren yerlerde bir offsetof
sonucunun kullanılması, C4644 veya C2975 uyarısını veren kodla sonuçlanabilir.
Aşağıdaki kod C4644'i varsayılan ve modlarda ve /std:c++17
C2975'i modda /permissive-
yükseltir:
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;
}
}
Hatayı düzeltmek için aracılığıyla <cstddef>
tanımlandığı gibi kullanınoffsetof
:
#include <cstddef>
struct Data {
int x;
};
int main()
{
switch (0) {
case offsetof(Data, x): return 0;
default: return 1;
}
}
Paket genişletmeye tabi temel sınıflardaki cv-niteleyicileri
Microsoft C++ derleyicisinin önceki sürümleri, paket genişletmeye tabi olduğunda bir temel sınıfın cv-niteleyicileri olduğunu algılamadı.
Visual Studio 2017 sürüm 15.8'de /permissive-
, modda aşağıdaki kod C3770'i yükseltir:
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
anahtar sözcük ve iç içe-ad-tanımlayıcıları
Modunda /permissive-
, derleyici artık bağımlı bir iç içe-ad-tanımlayıcıdan sonra geldiğinde bir şablon-adın önüne anahtar sözcüğünü gerektirir template
.
Modda aşağıdaki kod /permissive-
artık C7510'a yükseltir:
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
}
};
Hatayı düzeltmek için aşağıdaki örnekte gösterildiği gibi deyimine Base<T>::example<int>();
anahtar sözcüğünü ekleyintemplate
:
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>();
}
};
15.9'da uyumluluk iyileştirmeleri
, []
, >>
ve işleçleri ->*
için soldan sağa değerlendirme sırası<<
C++17'den başlayarak , []
, >>
ve <<
işleçlerinin ->*
işlenenleri soldan sağa sırayla değerlendirilmelidir. Derleyicinin bu sırayı garanti edemediği iki durum vardır:
İşlenen ifadelerden biri değer tarafından geçirilen bir nesneyse veya değer tarafından geçirilen bir nesne içeriyorsa veya
kullanılarak
/clr
derlendiğinde ve işlenenlerden biri bir nesnenin veya dizi öğesinin alanıdır.
Derleyici, soldan sağa değerlendirme garantisi vermediğinde C4866 uyarısını yayar. Bu işleçlerin soldan sağa sıra gereksinimi C++17'de sunulduğundan, derleyici bu uyarıyı yalnızca veya daha sonra belirtilirse /std:c++17
oluşturur.
Bu uyarıyı çözmek için önce işlenenlerin soldan sağa değerlendirmesinin gerekli olup olmadığını göz önünde bulundurun. Örneğin, işlenenlerin değerlendirmesi sıralamaya bağımlı yan etkiler üretebilirken gerekli olabilir. İşlenenlerin değerlendirilme sırasının birçok durumda gözlemlenebilir bir etkisi yoktur. Değerlendirme sırasının soldan sağa olması gerekiyorsa, bunun yerine işlenenleri const başvurusuyla geçirip geçiremeyeceğinizi düşünün. Bu değişiklik aşağıdaki kod örneğindeki uyarıyı ortadan kaldırır:
// 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>>
};
Üye diğer ad şablonlarındaki tanımlayıcılar
Üye diğer adı şablon tanımında kullanılan bir tanımlayıcı kullanılmadan önce bildirilmelidir.
Derleyicinin önceki sürümlerinde aşağıdaki koda izin veriliyordu. Visual Studio 2017 sürüm 15.9'da/permissive-
, derleyici modunda C3861'i yükseltir:
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;
Hatayı düzeltmek için önce from_template_t
bildirinfrom_template
.
Modül değişiklikleri
Visual Studio 2017, sürüm 15.9'da, modüller için komut satırı seçenekleri modül oluşturma ve modül tüketimi tarafları arasında tutarlı olmadığından derleyici C5050'yi yükseltir. Aşağıdaki örnekte iki sorun vardır:
Tüketim tarafında (main.cpp) seçenek
/EHsc
belirtilmez.C++ sürümü oluşturma tarafında ve
/std:c++14
tüketim tarafındadır/std:c++17
.
cl /EHsc /std:c++17 m.ixx /experimental:module
cl /experimental:module /module:reference m.ifc main.cpp /std:c++14
Derleyici, şu iki durum için de C5050'yi yükseltir:
warning C5050: Possible incompatible environment while
importing module 'm': mismatched C++ versions.
Current "201402" module version "201703".
Derleyici ayrıca dosya üzerinde oynandığı her durumda C7536'ya .ifc
yükseltir. Modül arabiriminin üst bilgisi, altındaki içeriğin SHA2 karması içerir. İçeri aktarma işleminde .ifc
dosya karma olarak eklenir, ardından üst bilgide sağlanan karmaya göre denetlenilir. Bunlar eşleşmezse C7536 hatası oluşur:
error C7536: ifc failed integrity checks.
Expected SHA2: '66d5c8154df0c71d4cab7665bab4a125c7ce5cb9a401a4d8b461b706ddd771c6'
Diğer adları ve çıkarılmamış bağlamları içeren kısmi sıralama
Uygulamalar, çıkarılmayan bağlamlardaki diğer adları içeren kısmi sıralama kurallarında ayrılır. Aşağıdaki örnekte GCC ve Microsoft C++ derleyicisi (modda /permissive-
) bir hata oluştururken Clang kodu kabul eder.
#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;
}
Önceki örnek C2668'i yükseltir:
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>)'
Uygulama ayrılığı, C++ standart ifadesindeki bir regresyondan kaynaklanır. Çekirdek sorun 2235'e çözüm, bu aşırı yüklemelerin sıralanması için bazı metinleri kaldırdı. Geçerli C++ standardı, bu işlevleri kısmen sıralamak için bir mekanizma sağlamaz, bu nedenle belirsiz olarak kabul edilirler.
Geçici bir çözüm olarak, bu sorunu çözmek için kısmi sıralamaya güvenmemenizi öneririz. Bunun yerine, belirli aşırı yüklemeleri kaldırmak için SFINAE kullanın. Aşağıdaki örnekte, uzmanlığı olduğunda Alloc
ilk aşırı yüklemeyi kaldırmak için bir A
yardımcı sınıfı IsA
kullanırız:
#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;
}
Şablonlu işlev tanımlarında geçersiz ifadeler ve değişmez olmayan türler
Geçersiz ifadeler ve değişmez değer olmayan türler artık açıkça özelleştirilmiş şablonlu işlevlerin tanımlarında doğru şekilde tanılanıyor. Daha önce bu tür hatalar işlev tanımı için gösterilmiyordu. Ancak, geçersiz ifade veya değişmez olmayan tür, sabit bir ifadenin parçası olarak değerlendirilirse yine de tanılanmış olabilir.
Visual Studio'nun önceki sürümlerinde aşağıdaki kod uyarı olmadan derlenir:
void g();
template<typename T>
struct S
{
constexpr void f();
};
template<>
constexpr void S<int>::f()
{
g(); // C3615 in 15.9
}
Visual Studio 2017 sürüm 15.9'da kod C3615 hatasını oluşturur:
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'.
Hatadan kaçınmak için, işlevinin constexpr
f()
açık örneğinden niteleyiciyi kaldırın.