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 constolması 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-initializationolduğ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 fkaldı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 CStringoluş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 constbildirinoperator 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::pairtü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 intbildirini.

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 BitBltve 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.ExperimentalAttributedekore 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 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ş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 /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 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_constructiblekarar 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 /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şkeni 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ışı 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_mapmapsetdaha 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::mapdüğü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_typedö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::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ş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:

  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ı 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, 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 noexceptthrow(<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++17devam 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 inlinekullanı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_locketkinleş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

P0017R1

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

P0127R2

Modunda /std:c++17 , derleyici artık ile autobildirilen 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 floatdoubleiçin üç yeni aşırı yükleme std::hypotekler ve long doublebunları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_codehata 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 , compareve find üye işlevlerinde lengthyapı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 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ü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 typenamederleyici 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 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 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 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 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 stdiletme 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 /WXile /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_castbir 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 /clrderlendiğ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_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 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 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 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.

Ayrıca bkz.

Microsoft C/C++ dil uyumluluğu