Visual Studio 2017'de C++ Uyumluluğu iyileş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 sonra sürüme göre iyileştirmeler listelenmiştir. Belirli bir sürümdeki değişikliklere doğrudan atlamak 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 iyileş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. Derleyicinin geçerli durumu için bkz. 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şkeni 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'te 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 ifade değerlendirmesinde yaşam süresi başlayan nesnelerin if ve switch deyimleri, döngü deyimleri ve mutasyonu gibi belirli türde bildirimleri içermesine constexpr izin verilir. Artık statik olmayan bir constexpr üye işlevinin örtük olarak constolması gerekmez. Daha fazla bilgi için bkz . İşlevlerdeki kısıtlamaları constexpr 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]] derleyiciye, geçiş davranışının amaçlandığına dair bir ipucu olarak switch deyimleri bağlamında 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ürmez. Bu değişiklik, içindeki aralıklar ve tamamlanmış ancak tam olarak yayımlanmamış Aralıklar range-v3 Teknik Belirtimi tarafından kullanılan bir sentinel döndürmeyi sağlarend(). Daha fazla bilgi için bkz. P0184R0 - Generalizing the Range-Based for Loop.

Kopyala-liste-başlatma

Visual Studio 2017, başlatıcı listelerini kullanarak nesne oluşturmayla ilgili derleyici hatalarını doğru bir şekilde oluşturur. Bu hatalar Visual Studio 2015'te yakalanmadı ve kilitlenmelere veya tanımlanmamış çalışma zamanı davranışına yol açabilir. içinde öğesine göreN4594 13.3.1.7p1copy-list-initialization, derleyicinin aşırı yükleme çözümlemesi için açık bir oluşturucuyu dikkate almaları gerekir. Ancak, belirli bir aşırı yükleme seçilirse hata oluşturması gerekir.

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 copy-list-initialization işlemini normal kopya başlatma ile aynı şekilde işledi: 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

Visual Studio 2017, koşullu değerlendirme işleminin sol işleneni bir bağlamda geçerli olmadığında doğru bir constexpr hata oluşturur. Aşağıdaki kod Visual Studio 2015'te derlenmiş ancak C3615'i yükselttiği Visual Studio 2017'de derlenmez:

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 'den fniteleyiciyi constexpr kaldırın.

Variadic işlevlerine geçirilen sınıf türleri

Visual Studio 2017'de, gibi printf bir variadic işlevine geçirilen sınıfların veya yapıların önemsiz olarak kopyalanabilir olması gerekir. 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 CStringoluşturulan ve yönetilen dizeler için sağlanan operator LPCTSTR() , bir nesneyi biçim dizesi tarafından beklenen C işaretçisine atamak 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 bir oluşturucu çağrısı aracılığıyla bir sınıf nesnesi oluştururken cv niteleyicisini 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ına neden olur:

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

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

Hatayı düzeltmek için olarak constbildirinoperator int().

Şablonlardaki nitelenmiş adlar üzerinde erişim denetimi

Derleyicinin önceki sürümleri bazı şablon bağlamlarında nitelenmiş adlara erişimi denetlemedi. Bu sorun, bir adın erişilemezliği nedeniyle değiştirmenin başarısız olması beklenen SFINAE davranışını engelleyebilir. Derleyici işlecin yanlış aşırı yüklemesini yanlış çağırdığından çalışma zamanında kilitlenmeye veya beklenmeyen bir davranışa neden olmuş olabilir. Visual Studio 2017'de bir derleyici hatası oluştu. 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.
}

Eksik şablon bağımsız değişken listeleri

Visual Studio 2015 ve önceki sürümlerde, derleyici tüm eksik şablon bağımsız değişken listelerini tanılamadı. Eksik şablonun bir şablon parametre listesinde ne zaman göründüğüne dikkat etmez: ö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ışı da dahil olmak üzere öngörülemeyen davranışlara neden olabilir. Aşağıdaki kod Visual Studio 2015'te derlenmiş ancak Visual Studio 2017'de bir hata üretir.

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

expression-SFINAE'yi desteklemek için, derleyici artık şablonlar örneği oluşturulurken 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 uzmanlık bulunursa, örnek oluşturma süresine kadar ertelenmiyor. Hemen işlenir ve sonuçta ortaya çıkan hatalar o anda 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ılmaması anlamına gelir. Visual Studio 2015 ve önceki sürümlerde 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ı tetikler:

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 yoksaydı). Bir değer sınıfının varsayılan olarak başlatılması her zaman üyeleri sıfırdan 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 adları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ı dallanmasını etkinleştirmek için deyimler içerebilir if constexpr . Daha fazla bilgi için bkz if constexpr . deyimler.

Başlatıcıları olan 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. [[nodiscard]] özniteliği, 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++'da ö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++'da öznitelikler.

Yapılandırılmış bağlamalar

Artık tek bir bildirimde, bir değer bir dizi, std::tuple veya veya olduğunda ya da std::pairtüm genel statik olmayan veri üyelerine sahip olduğunda bileşenleri için tek tek adlarla bir değer 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 yapı kuralları

Artık daraltılmayan kapsamlı sabit listeleri için örtük bir dönüştürme vardır. Kapsamı belirlenmiş bir sabit listesi temel türünden numaralandırmanın kendisine dönüştürür. Dönüştürme, tanımı numaralandırıcıyı tanıtmadığında 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ğer tarafından 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ışı register anahtar sözcüğü kaldırma

register Daha ö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 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 intbildirini.

Tür özellikleri için ön koşul denetimleri

Visual Studio 2017 sürüm 15.3, standardı daha katı bir şekilde uygulamak için tür özelliklerine yönelik ön koşul denetimlerini geliştirir. Bu tür denetimlerden biri atanabilir denetimdir. 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 hazırlamada 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 copy-constructor'ını çağırır veya kullanır BitBlt. Bu da çalışma zamanında tanımsız davranışa neden olabilir.

Şimdi derleyici, derleme zamanında bu hatayı bulursa bir uyarı yayar: silinen kopya ctor'ı olan yerel bir nesne değere göre yerel ve yönetilen sınır arasında geçirilir. Derleyicinin derleme zamanında bilmediği durumlar için, 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ı üretir:

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.ExperimentalAttributedonatılmıştır. 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 özniteliğiyle önceden düzenlenmiştir ve bu API'lere yapılan çağrılar artık bu derleyici uyarısını tetiklemiştir. Daha yeni Windows SDK'larında özniteliği tüm gönderilen türlerden kaldırılı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ı üretir:

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 hata üretir. Aşağıdaki kod şimdi 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ını üretir.

Erişilemeyen bir temel sınıfa dönüştürme

Visual Studio 2017 sürüm 15.3, bir türü erişilemez bir temel sınıfa dönüştürmeye çalıştığınızda bir hata üretir. Aşağıdaki kod bozuktur ve çalışma zamanında kilitlenmeye neden olabilir. Derleyici şimdi 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 döndürür.

Visual Studio'nun önceki sürümlerinde aşağıdaki kötü biçimlendirilmiş kod çalışma zamanının 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)burada m bir "bileşik üye belirticisi" kullanıldığında, seçeneğiyle /Wall derlendiğinde bir uyarıyla sonuçlanır. Aşağıdaki kod bozuktur 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ı pragma ile devre dışı bırakın veya kodu kullanmamak offsetofiç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şlevi ile 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 hatayla sonuçlanır. Aşağıdaki kod C4597 hatasını üretir:

#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ğırmamak için 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ğlama belirtimlerinden önce extern "C" uygulanırsa __declspec(...) derleyici artık öznitelikleri yoksayar. 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/WXderlenen 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 decltypeilişkilendirilmiş ifade bağlamında silinmiş bir yıkıcıya yapılan çağrının ne zaman gerçekleştiğini algılamadı. Visual Studio 2017 sürüm 15.3'te aşağıdaki kod C2280 hatasını üretir:

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ış sabit değişkenler

Visual Studio 2017 RTW sürümünde regresyon vardı: C++ derleyicisi başlatılmamış const bir değişken için tanılama yayımlamaz. 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 şimdi dört bildirimin tümü için düzey 2 C4091 uyarısı üretir:

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 bir yan etkiye (RAII gibi) sahip olması amaçlandığı durumlarda, nesneye bir ad verilmelidir.

Uyarı altında hariç tutulur /Wv:18 ve uyarı düzeyi W2 altında 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 Microsoft C++ derleyicisinin özel servis talebi için kitaplık yazarlarını zorunlu kılmıştır std::is_convertible<...> . 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_constructiblekarar verirken bir yıkıcının özel olup olmadığını yoksaydı. Ş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 bir ş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ğımlı 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çerse beklenmeyen çalışma zamanı davranışına yol açabilir. Genellikle, hatanın nedeni yerel işlev bildiriminin yanlış imza olmasıdır. Aşağıdaki örnekte, Visual Studio 2017 sürüm 15.3 C2660'ı doğru bir ş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 çözmek 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 çözmek için başlatıcı listesini bildirimlerle aynı sırada 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şur.

Bu uyarı varsayılan olarak kapalıdır ve yalnızca ile /Wallderlenen 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şken işaretlendiğinde externbile 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:externConstexprdoğ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ışı bırakılan throw() belirtim, için noexcept(true)tam olarak bir diğer ad olarak tutulur. Daha fazla bilgi için bkz . Dinamik özel durum belirtimi kaldırma ve noexcept.

not_fn()

P0005R4not_fn ve not2öğesinin not1 yerini alır.

Yeniden ifade etme enable_shared_from_this

P0033R1enable_shared_from_this 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, düğümlerin ilişkilendirilebilir kapsayıcılardan (yani , mapset, , unordered_mapunordered_set) ayıklanmasına olanak tanır. Bu işlem aynı kapsayıcıya veya aynı düğüm türünü kullanan farklı bir kapsayıcıya değiştirilebilir ve yeniden eklenebilir. (Yaygın bir kullanım örneği, bir düğümü içinden std::mapayıklamak, anahtarı değiştirmek ve yeniden eklemektir.)

Vestigial kitaplık bölümlerini kullanım dışı bırakılıyor

P0174R2 C++ standart kitaplığının birkaç özelliğinin yerini yıllar içinde daha yeni özellikler aldı veya yararlı veya sorunlu olmayan başka özellikler bulundu. 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'nin öncesinde 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 semantikler belirsizdi. Sorun ekstruktörleri 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ı için destek sağlar.

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

P0414R2 Kitaplık TemelLeri'nden shared_ptr C++17'ye yapılan değişiklikleri birleştirme. [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 anahtarlara sahip ilişkilendirilebilir kapsayıcılar ve benzersiz anahtarlara sahip sıralanmamış kapsayıcılar, iç içe türü insert_return_typedöndüren bir üye işlevine insert sahiptir. Bu dönüş türü artık kapsayıcının Yineleyicisi ve NodeType'larında parametreleştirilmiş bir türün uzmanlığı 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::tr1dahil 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şaretlendi.

içindeki std::tr2::sys<experimental/filesystem> ad alanı artık varsayılan olarak altında /std:c++14 bir kullanımdan kaldırma uyarısı yayar ve artık varsayılan olarak ve altında /std:c++17 ve daha sonra kaldırılır.

<iostream> Standart olmayan bir uzantıdan (sınıf içi açık özelleştirmeler) kaçınarak uyumluluğun iyileştirilmesi.

Standart kitaplık artık değişken şablonları dahili olarak kullanır.

Standart kitaplık, C++17 derleyici değişikliklerine yanıt olarak güncelleştirildi. Güncelleştirmeler tür sistemine öğesinin eklenmesini noexcept ve dinamik özel durum belirtimlerinin 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 ve pack-non-pack). Derleyici hatasını ortadan kaldırmak için farklardan birini kaldırın. Daha sonra derleyici, işlevleri kesin bir şekilde 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 nesnesi için hiçbir zaman eşleşmez. Derleyici şimdi bu kuralı doğru şekilde kabul eder ve C4843 düzey 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şaretlendi. 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şaretlendi

/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 daha fazla durumda C4189 uyarısı gösterilir:

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 dağıtılır. 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 olarak 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'u bastırın.

/* C only */

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

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

__declspec bağlantısı olan extern "C" öznitelikler

Visual Studio'nun önceki sürümlerinde, bağlama belirtiminin öncesinde extern "C" uygulandığında __declspec(...) derleyici öznitelikleri yoksaydı__declspec(...). Bu davranış, olası çalışma zamanı etkileriyle birlikte kullanıcının amaçlamamasına neden olan kodun oluşturulmasına 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 birlikte gelen 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. Bu uyarının Windows SDK üst bilgilerinden geldiğini gördüğünüzde şu eylemleri gerçekleştirebilirsiniz:

  1. Visual Studio 2017 sürüm 15.5 sürümüyle birlikte gelen en son Windows SDK'sına geçin.

  2. 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 externbile derleyici her zaman bir constexpr değişken iç bağlantısı 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 constexprbir 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, bir tür soyut olduğunda işaretçi türü olmayan bir karşılaştırma başarısız olabileceğinden, is_convertible kullanırken işaretçi türlerini karşılaştırmanız gerekir:

#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 noexceptthrow(<type list>) bir diğer addır ve throw(...) kaldırılır ve belirli türler içerebilirnoexcept. Bu değişiklik, C++14 veya önceki sürümlerle uyumlu kodda kaynak uyumluluk sorunlarına neden olabilir. Anahtar /Zc:noexceptTypes- , genel olarak C++17 modunu kullanı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 uyarı C5043 ile /permissive- daha fazla eşleşmeyen özel durum belirtimini tanılar.

Aşağıdaki kod, geçiş uygulandığında Visual Studio 2017 sürüm 15.5'te /std:c++17 C5043 ve C5040 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
};

kullanırken /std:c++17hataları 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 inlinekullanılır. Bu, 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 değildir 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 ile 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 __declspec(nothrow) varsayılan işlevden kaldırın veya gerekli özel durum işleme ile birlikte işlev için bir tanım seçip = default 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 ile, belirli "çağrılabilir" türleri eşleştirmeye yönelik kısmi özelleştirmeler, işaretçiler-noexcept-functions için eksik bir kısmi özelleştirme nedeniyle derlenmeyebilir veya birincil şablonu seçemeyebilir.

Bu gibi 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 altında /std:c++14 derlenmiş ancak C2027 hatasıyla başarısız oluyor /std:c++17 :

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ığının Temelleri V1

P0220R1 , C++17 için Kitaplık Temelleri Teknik Belirtimini standart olarak içerir. , , , <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 geliştirme

P0739R0 tutarlı kullanımını etkinleştirmek için parametresi scoped_lock listesinin scoped_lockönüne geçinadopt_lock_t. 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 ifade etme

P0136R1 , bir oluşturucuyu adlandıran bir using bildirimin artık daha fazla türetilmiş sınıf oluşturucuları bildirmek yerine ilgili 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ş toplu başlatma

P0017R1

Bir 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 ve sonraki sürümlerinin altında /std:c++17 , türetilmiş türdeki bir nesneyi başlatmak için artık boş ayraç 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şlatmanın Base , genişletilmiş toplama başlatma kuralının bir parçası olarak doğrudan gerçekleştiği anlamına gelir. Daha önce özel Base oluşturucu oluşturucu aracılığıyla Derived çağrıldı ve arkadaş bildirimi nedeniyle başarılı oldu. Aşağıdaki örnekte, Visual Studio sürüm 15.7'de /std:c++17 modda 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

P0127R2

Modunda /std:c++17 , derleyici artık ile autobildirilen tür olmayan bir şablon bağımsız değişkeninin türünü alabilir:

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) ile ilişkili 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'deki C++17 /std:c++17 kodu modda 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 ve dizeler arasında dönüştürmeler için düşük düzeyli, yerel ayardan bağımsız işlevler.

C++20: Gereksiz bozulmayı ö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 standartta birleştirilir.

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

P0030R1 her biri üç giriş parametresi olan , doubleve long doubletürleri floatiçin öğesine üç yeni aşırı yükleme std::hypotekler.

C++17: <filesystem>

P0218R1 Dosya Sistemi TS'sini birkaç sözcük değişikliğiyle standart olarak 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ı

P0433R2, sınıf şablonu bağımsız değişkeni kesintisi için destek ekleyen P0091R3'ün C++17 benimsemesinden yararlanmak için STL'ye Güncelleştirmeler.

C++17: Temel dize dönüştürmelerini onarma

P0682R1 Yeni temel dize dönüştürme işlevlerini P0067R5'ten yeni bir üst bilgiye <charconv> taşıyın ve hata işlemeyi yerine std::error_codekullanacak std::errc şekilde değiştirme de dahil olmak üzere başka geliştirmeler yapın.

C++17: constexpr için char_traits (kısmi)

P0426R1std::traits_type Sabit ifadelerde kullanılabilir hale getirmek std::string_view için , compareve find üye işlevlerinde lengthyapılan değişiklikler. (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 templatesbir ö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 templatesbir önkoşuldur.

Aşağıdaki örnekte, Visual Studio 15.6 ve önceki sürümlerdeki derleyici birincil sınıf şablonunda olarak çözümlenmiştir D::typeB<T>::type .

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

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

Modda Visual Studio 2017 sürüm 15.7/std:c++17, D deyiminde using anahtar sözcüğünü gerektirirtypename. olmadan typenamederleyici C4346 uyarısını 'B<T*>::type': dependent name is not a type ve C2061 hatasını döndürür: : 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ışı

Modda Visual Studio 2017 sürüm 15.7'de /std:c++17, C4834 uyarı düzeyi W3'ten W1'e yükseltilir. uyarısını öğesine atama ile veya derleyiciye voidgeç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 listesine yanlışlıkla hatasız izin veriliyordu. Visual Studio 2017 sürüm 15.7'de bir derleyici hatası oluşur.

Visual Studio 2017 sürüm 15.7'deki aşağıdaki kod örneği C2614 hatasına neden olur:

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 şimdi C2078'i yükseltir. 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ınacaktı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 '=' öncesinde yerleştirilen ö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 asılsız bir ad bırakacaktı. Şimdi, bağımlı olmayan adların şablon gövdesine bağlı olmasını gerektirir.

Bu bildirimin ortaya çıkarabilmesinin bir yolu, 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. Bu kod artık bir hata olarak kabul edilir. Böyle durumlarda, örneğin bir işaretçi ekleyerek değişkeni temel sınıf türüyle niteleyerek veya başka bir this-> şekilde bağımlı hale getirerek örnekleme zamanında aranmaya zorlayabilirsiniz.

Modunda /permissive- , aşağıdaki kod şimdi 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 bir şablon iletme bildirimi unwind_type.hppiçin MSVC'ye özgü bir geçici çözüm sağlanmıştır. /permissive- Visual Studio 2017 sürüm 15.8(_MSC_VER==1915 ile başlayan 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ı olduğundan bu geçici çözüm gereksiz koruma sağlar. C3861: 'unwind_type': identifier not foundhatası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 stdiletme bildirimleri veya tanımları eklemesine izin vermez. Ad alanına veya ad alanı içindeki std bir ad std alanına bildirimler veya tanımlar 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 stdiletme bildirimleri ekleyen mevcut kodu bozar. Yeni bir uyarı olan C4643, bu tür kaynak sorunları belirlemenize yardımcı olur. Uyarı modda /default etkindir ve varsayılan olarak kapalıdır. veya /WXile /Wall derlenen programları etkiler.

Aşağıdaki kod şimdi 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 iletme bildirimi yerine bir yönerge kullanın #include :

#include <vector>

Kendilerine temsilci seçen oluşturucular

C++ standardı, temsilci seçme oluşturucu kendisine temsilci olarak atandığında derleyicinin bir tanılama yayması gerektiğini önerir. ve /std:c++latest modlarındaki /std:c++17 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 belirleyin:

class X {
public:

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

offsetof sabit ifadelerle

offsetof geleneksel olarak gerektiren reinterpret_castbir makro kullanılarak uygulanmıştır. Bu kullanım, sabit 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ç öğesi ()__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 koda neden olabilir.

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ığı şekilde 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ıflarda cv-niteleyicileri

Microsoft C++ derleyicisinin önceki sürümleri, bir temel sınıfın da paket genişletmeye tabi olması durumunda cv-niteleyicileri olduğunu algılamamıştı.

Visual Studio 2017 sürüm 15.8'de /permissive- , modda aşağıdaki kod C3770'i oluşturur:

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ından önce 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 nesne olduğunda veya değer tarafından geçirilen bir nesne içerdiğinde veya

  • kullanılarak /clrderlendiğinde ve işlenenlerden biri bir nesnenin veya dizi öğesinin alanıdır.

Derleyici, soldan sağa değerlendirmeyi garanti etmediğ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ğerlendirilmesi sıralamaya bağımlı yan etkiler üretebilirken gerekli olabilir. İşlenenlerin değerlendirilme sırası birçok durumda gözlemlenebilir bir etkiye sahip değildir. 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 şablonu 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_tbildirinfrom_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 oynanan 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ılmayan bağlamları içeren kısmi sıralama

Uygulamalar, çıkarılmayan bağlamlarda 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ışması, C++ standart ifadesindeki bir regresyondan kaynaklanır. Çekirdek sorun 2235'in çözümü, bu aşırı yüklemelerin sıralanması için izin veren 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, bir uzmanlığı olduğunda Alloc ilk aşırı yüklemeyi kaldırmak için bir Ayardı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 değer 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, bir sabit ifadenin parçası olarak değerlendirilirse geçersiz ifade veya değişmez değer olmayan tür 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 constexprf()açık örneğinden niteleyiciyi kaldırın.

Ayrıca bkz.

Microsoft C/C++ dil uyumluluğu