Visual C++ 2003 ~ 2015의 새로운 기능Visual C++ What's New 2003 through 2015

참고 Visual Studio 2017에 대한 자세한 내용은 Visual Studio 2017의 Visual C++에 대한 새로운 기능Visual Studio 2017의 Visual C++에서 규칙 향상을 참조하세요.Note For information about Visual Studio 2017, see What's new for Visual C++ in Visual Studio 2017 and Conformance Improvements in Visual C++ in Visual Studio 2017.

Visual C++ 2015 이상 버전에서는 컴파일러 규칙 개선 작업이 진행 중이므로 컴파일러에서 기존 소스 코드를 인식하는 방식이 변경될 수 있습니다.In Visual C++ 2015 and later, ongoing improvements to compiler conformance can sometimes change how the compiler understands your existing source code. 이로 인해 빌드 중 새로운 오류 또는 다른 오류가 발생하거나, 이전에 빌드되어 올바르게 실행되는 것처럼 보이는 코드가 다르게 동작할 수도 있습니다.When this happens, you might encounter new or different errors during your build, or even behavioral differences in code that previously built and seemed to run correctly.

다행히 이러한 차이는 대부분의 소스 코드에 거의 또는 전혀 영향을 주지 않으며, 차이를 해결하기 위해 소스 코드 변경이나 기타 변경이 필요한 경우에도 대체로 간단히 처리할 수 있는 사소한 수정입니다.Fortunately, these differences have little or no impact on most of your source code and when source code or other changes are needed to address these differences, fixes are usually small and straight-forward. 이전에는 허용되는 소스 코드였지만 변경해야 할 수 있는 코드(이전) 및 수정 코드(이후)의 많은 예가 포함되어 있습니다.We've included many examples of previously-acceptable source code that might need to be changed (before) and the fixes to correct them (after).

이러한 차이가 소스 코드나 다른 빌드 아티팩트에 영향을 줄 수도 있지만 Visual C++ 버전 업데이트 간의 이진 호환성에는 영향을 주지 않습니다.Although these differences can affect your source code or other build artifacts, they don't affect binary compatibility between updates to Visual C++ versions. 보다 심각한 종류의 변경인 주요 변경 내용은 이진 호환성에 영향을 줄 수 있지만 이러한 종류의 이진 호환성 중단은 Visual C++의 주 버전 간에만 발생합니다.A more-severe kind of change, the breaking change can affect binary compatibility, but these kinds of binary compatibility breaks only occur between major versions of Visual C++. 예를 들어 Visual C++ 2013과 Visual C++ 2015 간에 발생합니다.For example, between Visual C++ 2013 and Visual C++ 2015. Visual C++ 2013과 Visual C++ 2015 사이에 발생한 주요 변경 내용에 대한 자세한 내용은 Visual C++ 변경 기록 2003 - 2015를 참조하세요.For information on the breaking changes that occurred between Visual C++ 2013 and Visual C++ 2015, see Visual C++ change history 2003 - 2015.

Visual C++ 2015의 규칙 향상Conformance Improvements in Visual C++ 2015

  • /Zc:forScope- 옵션/Zc:forScope- option

    /Zc:forScope- 컴파일러 옵션은 사용되지 않으므로 이후 릴리스에서 제거될 예정입니다.The compiler option /Zc:forScope- is deprecated and will be removed in a future release.

    Command line warning  D9035: option 'Zc:forScope-' has been deprecated and will be removed in a future release  
    

    옵션은 대개 표준에 따라 범위를 벗어나야 하는 지점 뒤에서 루프 변수를 사용하는 비표준 코드를 허용하려고 사용됩니다.The option was usually used in order to allow nonstandard code that uses loop variables after the point where, according to the standard, they should have gone out of scope. /Za를 사용하지 않으면 루프 끝에 for 루프 변수를 항상 사용할 수 있으므로 /Za 옵션으로 컴파일할 경우에만 필요합니다.It was only necessary when you are compiling with the /Za option, since without /Za, using a for loop variable after the end of the loop is always allowed. 표준 준수가 중요하지 않으면(예: 코드가 다른 컴파일러에 이식 가능하지 않은 경우) /Za 옵션을 해제하거나 언어 확장 사용 안 함 속성을 아니요로 설정할 수 있습니다.If you don't care about standards conformance (for example, if your code isn't meant to portable to other compilers), you could turn off the /Za option (or set the Disable Language Extensions property to No). 이식 가능한 표준 규격 코드를 작성해야 하면 변수의 선언을 루프 외부 지점으로 이동하여 표준을 따르도록 코드를 다시 작성해야 합니다.If you do care about writing portable, standards-compliant code, you should rewrite your code so that it conforms to the standard by moving the declaration of such variables to a point outside the loop.

    // zc_forScope.cpp  
    // compile with: /Zc:forScope- /Za  
    // C2065 expected  
    int main() {  
       // Uncomment the following line to resolve.  
       // int i;  
       for (int i =0; i < 1; i++)  
          ;  
       i = 20;   // i has already gone out of scope under /Za  
    }  
    
  • /Zg 컴파일러 옵션/Zg compiler option

    /Zg 컴파일러 옵션(함수 프로토타입 생성)은 더 이상 사용할 수 없습니다.The /Zg compiler option (Generate Function Prototypes) is no longer available. 이 컴파일러 옵션은 이미 사용되지 않습니다.This compiler option was previously deprecated.

  • mstest.exe를 사용하여 명령줄에서 C++/CLI에 대한 단위 테스트를 더 이상 실행할 수 없습니다.You can no longer run unit tests with C++/CLI from the command-line with mstest.exe. 대신에 vstest.console.exe를 사용하세요.Instead, use vstest.console.exe. VSTest.Console.exe 명령줄 옵션을 참조하세요.See VSTest.Console.exe command-line options.

  • mutable 키워드mutable keyword

    이전에 오류 없이 컴파일했던 위치에서 mutable 저장소 클래스 지정자가 더 이상 허용되지 않습니다.The mutable storage class specifier is no longer allowed in places where previously it compiled without error. 현재 컴파일러에서는 오류 C2071(저장소 클래스가 잘못되었습니다.)을 표시합니다.Now, the compiler gives error C2071 (illegal storage class). 표준에 따라 mutable 지정자는 클래스 데이터 멤버의 이름에만 적용되고 const 또는 static으로 선언된 이름과 참조 멤버에는 적용할 수 없습니다.According to the standard, the mutable specifier can be applied only to names of class data members, and cannot be applied to names declared const or static, and cannot be applied to reference members.

    예를 들어, 다음 코드를 고려하세요.For example, consider the following code:

    struct S {  
        mutable int &r;  
    };  
    

    이전 Visual C++ 컴파일러 버전에서는 이를 허용했으나 현재 컴파일러에서는 다음 오류를 표시합니다.Previous versions of the Visual C++ compiler accepted this, but now the compiler gives the following error:

    error C2071: 'S::r': illegal storage class  
    

    오류를 수정하려면 중복 mutable 키워드를 제거하세요.To fix the error, simply remove the redundant mutable keyword.

  • char_16_t 및 char32_tchar_16_t and char32_t

    char16_t 또는 char32_t 형식은 현재 기본 제공으로 처리되므로 typedef에서 이들 형식을 별칭으로 더 이상 사용할 수 없습니다.You can no longer use char16_t or char32_t as aliases in a typedef, because these types are now treated as built-in. 사용자와 라이브러리 작성자가 char16_t 및 char32_t를 각각 uint16_t 및 uint32_t의 별칭으로 정의하는 것이 일반적이었습니다.It was common for users and library authors to define char16_t and char32_t as aliases of uint16_t and uint32_t, respectively.

    #include <cstdint>  
    
    typedef uint16_t char16_t; //C2628  
    typedef uint32_t char32_t; //C2628  
    
    int main(int argc, char* argv[])  
    {  
    uint16_t x = 1; uint32_t y = 2;  
    char16_t a = x;   
    char32_t b = y;   
    return 0;  
    }  
    

    코드를 업데이트하려면 typedef 선언을 제거하고 이들 이름과 충돌하는 다른 식별자의 이름을 바꿉니다.To update your code, remove the typedef declarations and rename any other identifiers that collide with these names.

  • 비형식 템플릿 매개 변수Non-type template parameters

    이제는 비형식 템플릿 매개 변수가 포함된 특정 코드에 명시적 템플릿 인수를 제공하면 형식 호환성 검사가 정확하게 수행됩니다.Certain code that involves non-type template parameters is now correctly checked for type compatibility when you provide explicit template arguments. 예를 들어 다음 코드는 이전 Visual C++ 버전에서는 오류 없이 컴파일되었습니다.For example, the following code compiled without error in previous versions of Visual C++.

    struct S1  
    {  
    void f(int);  
    void f(int, int);  
    };  
    
    struct S2  
    {  
    template <class C, void (C::*Function)(int) const> void f() {}  
    };  
    
    void f()  
    {  
    S2 s2;  
    s2.f<S1, &S1::f>();  
    }  
    

    템플릿 매개 변수 형식이 템플릿 인수와 일치하지 않기 때문에 현재 컴파일러에서 제대로 오류를 표시합니다. 매개 변수는 const 멤버의 포인터이나 f 함수는 비const입니다.The current compiler correctly gives an error, because the template parameter type doesn't match the template argument (the parameter is a pointer to a const member, but the function f is non-const):

    error C2893: Failed to specialize function template 'void S2::f(void)'note: With the following template arguments:note: 'C=S1'note: 'Function=S1::f'  
    

    코드에서 이 오류를 해결하려면 사용하는 템플릿 인수 형식이 템플릿 매개 변수의 선언된 형식과 일치해야 합니다.To address this error in your code, make sure that the type of the template argument you use matches the declared type of the template parameter.

  • __declspec(align)__declspec(align)

    컴파일러가 함수에서 __declspec(align) 을 더 이상 허용하지 않습니다.The compiler no longer accepts __declspec(align) on functions. 이는 항상 무시되었지만 현재는 컴파일러 오류가 생성됩니다.This was always ignored, but now it produces a compiler error.

    error C3323: 'alignas' and '__declspec(align)' are not allowed on function declarations  
    

    이 문제를 수정하려면 함수 선언에서 __declspec(align) 을 제거합니다.To fix this problem, remove __declspec(align) from the function declaration. 아무런 영향이 없으므로 제거해도 아무것도 변경되지 않습니다.Since it had no effect, removing it does not change anything.

  • 예외 처리Exception handling

    예외 처리에 대한 몇 가지 변경 내용이 있습니다.There are a couple of changes to exception handling. 먼저 예외 개체는 복사 가능하거나 이동 가능해야 합니다.First, exception objects have to be either copyable or movable. 다음 코드는 --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013에서 컴파일되었지만 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서는 컴파일되지 않습니다.The following code compiled in --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013, but does not compile in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015:

    struct S {  
    public:  
        S();  
    private:  
        S(const S &);  
    };  
    
    int main()  
    {  
        throw S(); // error  
    }  
    

    문제는 복사 생성자가 private이라는 점이므로 일반적인 예외 처리 과정으로는 개체를 복사할 수 없습니다.The problem is that the copy constructor is private, so the object cannot be copied as happens in the normal course of handling an exception. 복사 생성자가 explicit로 선언될 경우에도 마찬가지입니다.The same applies when the copy constructor is declared explicit.

    struct S {  
        S();  
        explicit S(const S &);  
    };  
    
    int main()  
    {  
        throw S(); // error  
    }  
    

    코드를 업데이트하려면 예외 개체에 대한 복사 생성자가 public이고 explicit로 표시되지 않아야 합니다.To update your code, make sure that the copy constructor for your exception object is public and not marked explicit.

    값으로 예외를 catch하려면 예외 개체가 복사 가능해야 합니다.Catching an exception by value also requires the exception object to be copyable. 다음 코드는 --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013에서 컴파일되었지만 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서는 컴파일되지 않습니다.The following code compiled in --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013, but does not compile in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015:

    struct B {  
    public:  
        B();  
    private:  
        B(const B &);  
    };  
    
    struct D : public B {  
    };  
    
    int main()  
    {  
        try  
        {  
        }  
        catch (D d) // error  
        {  
        }  
    }  
    

    참조에 대한 catch 의 매개 변수 형식을 변경하여 이 문제를 해결할 수 있습니다.You can fix this issue by changing the parameter type for the catch to a reference.

    catch(D& d)  
    {  
    }  
    
  • 매크로 뒤의 문자열 리터럴String literals followed by macros

    현재 컴파일러는 사용자 정의 리터럴을 지원합니다.The compiler now supports user defined literals. 따라서 중간 공백 없이 매크로 뒤의 문자열 리터럴은 오류나 예기치 않은 결과를 생성할 수 있는 사용자 정의 리터럴로 해석됩니다.As a consequence, string literals followed by macros without any intervening whitespace are interpreted as user-defined literals, which might produce errors or unexpected results. 예를 들어 이전 컴파일러에서는 다음 코드가 성공적으로 컴파일되었습니다.For example, in previous compilers the following code compiled successfully:

    #define _x "there"  
    char* func() {  
        return "hello"_x;  
    }  
    int main()  
    {  
        char * p = func();  
        return 0;  
    }  
    

    컴파일러에서 이 코드는 매크로 뒤의 문자열 리터럴 "hello"로 해석되고 “there”로 확장되었고 두 문자열 리터럴은 하나로 연결되었습니다.The compiler interpreted this as a string literal "hello" followed by a macro, which is expanded "there", and then the two string literals were concatenated into one. --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서 컴파일러는 이 코드를 사용자 정의 리터럴로 해석하지만 일치하는 사용자 정의 리터럴 _x가 정의되지 않았으므로 오류가 발생합니다.In --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015, the compiler interprets this as a user-defined literal, but since there is no matching user-defined literal _x defined, it gives an error.

    error C3688: invalid literal suffix '_x'; literal operator or literal operator template 'operator ""_x' not found  
    note: Did you forget a space between the string literal and the prefix of the following string literal?  
    

    이 문제를 수정하려면 문자열 리터럴과 매크로 사이에 공백을 추가합니다.To fix this problem, add a space between the string literal and the macro.

  • 인접 문자열 리터럴Adjacent string literals

    이전과 비슷하게 문자열 구문 분석의 관련 변경 내용 때문에 공백이 없는 인접 문자열 리터럴(전각 또는 반각 문자 문자열 리터럴)은 이전 Visual C++ 릴리스에서 하나의 연결된 문자열로 해석되었습니다.Similarly to the previous, due to related changes in string parsing, adjacent string literals (either wide or narrow character string literals) without any whitespace were interpreted as a single concatenated string in previous releases of Visaul C++. --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서는 현재 두 문자열 사이에 공백을 추가해야 합니다.In --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015, you must now add whitespace between the two strings. 예를 들어 다음 코드를 변경해야 합니다.For example, the following code must be changed:

    char * str = "abc""def";  
    

    두 문자열 사이에 공백을 추가하면 됩니다.Simply add a space in between the two strings.

    char * str = "abc" "def";  
    
  • Placement new 및 deletePlacement new and delete

    delete 연산자는 C++14 표준을 준수하도록 변경되었습니다.A change has been made to the delete operator in order to bring it into conformance with C++14 standard. 표준 변경에 대한 자세한 내용은 C++ 크기 지정된 할당 해제(영문)를 참조하세요.Details of the standards change can be found at C++ Sized Deallocation. 변경을 통해 size 매개 변수를 사용하는 전역 delete 연산자의 형식이 추가됩니다.The changes add a form of the global delete operator that takes a size parameter. 주요 변경 내용에 따르면 이전에는 placement new 연산자와 일치하도록 같은 서명으로 delete 연산자를 사용하면 placement new가 사용된 지점에서 컴파일러 오류(C2956)가 발생했습니다. 이 지점은 컴파일러가 해당하는 일치 delete 연산자를 식별하려고 하는 코드의 위치이기 때문입니다.The breaking change is that if you were previously using an operator delete with the same signature (to correspond with a placement new operator), you will receive a compiler error (C2956, which occurs at the point where the placement new is used, since that's the position in code where the compiler tries to identify an appropriate matching delete operator).

    void operator delete(void *, size_t) 함수는 C++11의 placement new 함수 "void * 연산자 new(size_t, size_t)"와 일치하는 placement delete 연산자였습니다.The function void operator delete(void *, size_t) was a placement delete operator corresponding to the placement new function "void * operator new(size_t, size_t)" in C++11. C++14 크기 지정된 할당 해제를 사용하면 이 delete 함수는 현재 usual deallocation 함수 (전역 delete 연산자)입니다.With C++14 sized deallocation, this delete function is now a usual deallocation function (global delete operator). 표준에 따르면 placement new를 사용하여 해당하는 delete 함수를 조회하고 usual deallocation 함수를 찾으면 프로그램에 잘못된 형식이 사용됩니다.The standard requires that if the use of a placement new looks up a corresponding delete function and finds a usual deallocation function, the program is ill-formed.

    예를 들어 코드에서 placement new 및 placement delete를 둘 다 정의한다고 가정합니다.For example, suppose your code defines both a placement new and a placement delete:

    void * operator new(std::size_t, std::size_t);  
    void operator delete(void*, std::size_t) noexcept;  
    

    정의한 placement delete 연산자와 새 전역 크기 지정된 delete 연산자 간에 함수 서명이 일치하기 때문에 문제가 발생합니다.The problem occurs because of the match in function signatures between a placement delete operator you've defined, and the new global sized delete operator. placement new 및 delete 연산자에 대해 size_t 이외의 다른 연산자를 사용할 수 있는지를 고려하세요.Consider whether you can use a different type other than size_t for any placement new and delete operators. size_t typedef의 형식은 컴파일러에 따라 결정되고 Visual C++에서는 부호 없는 int에 대한 typedef입니다.Note that the type of the size_t typedef is compiler-dependent; it is a typedef for unsigned int in Visual C++. 이 문제를 해결하려면 다음과 같은 열거된 형식을 사용하는 것이 좋습니다.A good solution is to use an enumerated type such as this:

    enum class my_type : size_t {};  
    

    그다음에 size_t 대신 이 형식을 두 번째 인수로 사용하도록 placement new 및 delete의 정의를 변경합니다.Then, change your definition of placement new and delete to use this type as the second argument instead of size_t. placement new에 대한 호출을 업데이트하여 새 형식을 전달하고(예: static_cast<my_type> 을 사용하여 정수 값에서 변환) new 및 delete의 정의를 업데이트하여 다시 정수 형식으로 캐스팅해야 합니다.You’ll also need to update the calls to placement new to pass the new type (for example, by using static_cast<my_type> to convert from the integer value) and update the definition of new and delete to cast back to the integer type. 여기에 열거형을 사용할 필요가 없고 size_t 멤버가 있는 클래스 형식도 사용할 수 있습니다.You don’t need to use an enum for this; a class type with a size_t member would also work.

    또 다른 솔루션은 placement new를 함께 제거하는 것입니다.An alternative solution is that you might be able to eliminate the placement new altogether. 코드에서 placement new를 사용하여 placement 인수가 할당되거나 삭제되는 개체 크기와 같은 메모리 풀을 구현하면 사용자 지정 메모리 풀 코드를 바꾸는 데는 크기 지정된 할당 해제 기능이 적합할 수 있고, placement 함수를 제거하고 placement 대신에 인수가 두 개인 delete 연산자만 사용할 수 있습니다.If your code uses placement new to implement a memory pool where the placement argument is the size of the object being allocated or deleted, then sized deallocation feature might be suitable to replace your own custom memory pool code, and you can get rid of the placement functions and just use your own two-argument delete operator instead of the placement functions.

    코드를 바로 업데이트하지 않으려면 컴파일러 옵션 /Zc:sizedDealloc-를 사용하여 이전 동작으로 되돌릴 수 있습니다.If you don't want to update your code immediately, you can revert to the old behavior by using the compiler option /Zc:sizedDealloc-. 이 옵션을 사용하면 인수가 두 개인 delete 함수가 존재하지 않으므로 placement delete 연산자와 충돌하지 않습니다.If you use this option, the two-argument delete functions don’t exist and won't cause a conflict with your placement delete operator.

  • 공용 구조체 데이터 멤버Union data members

    공용 구조체의 데이터 멤버는 더 이상 참조 형식을 포함할 수 없습니다.Data members of unions can no longer have reference types. --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013에서는 다음 코드가 성공적으로 컴파일되었지만 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서는 오류가 발생합니다.The following code compiled successfully in --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013, but produces an error in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015.

    union U1 {  
        const int i;  
    };  
    union U2 {  
       int &i;  
    };  
    union U3 {  
        struct {int &i;};  
    };  
    

    앞의 코드에서 발생하는 오류는 다음과 같습니다.The preceding code produces the following errors:

    test.cpp(67): error C2625: 'U2::i': illegal union member; type 'int &' is reference type  
    test.cpp(70): error C2625: 'U3::i': illegal union member; type 'int &' is reference type  
    

    이 문제를 해결하려면 참조 형식을 포인터 또는 값으로 변경합니다.To address this issue, change reference types either to a pointer or a value. 형식을 포인터로 변경하려면 공용 구조체 필드를 사용하는 코드를 변경해야 합니다.Changing the type to a pointer requires changes in the code that uses the union field. 코드를 값으로 변경하면 공용 구조체에 저장된 데이터가 변경되며, union 형식의 필드는 같은 메모리를 공유하므로 이 변경이 다른 필드에 영향을 미칩니다.Changing the code to a value would change the data stored in the union, which affects other fields since fields in union types share the same memory. 값 크기에 따라 공용 구조체 크기도 변경할 수 있습니다.Depending on the size of the value, it might also change the size of the union.

  • 현재 익명 공용 구조체는 표준을 더 준수합니다.Anonymous unions are now more conformant to the standard. 이전 컴파일러 버전에서는 익명 공용 구조체에 대한 명시적 생성자 및 소멸자를 생성했습니다.Previous versions of the compiler generated an explicit constructor and destructor for anonymous unions. 이 기능은 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서 삭제되었습니다.These are deleted in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015.

    struct S {  
      S();  
     };  
    
     union {  
      struct {  
       S s;  
      };  
     } u; // C2280  
    

    앞의 코드는 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서 다음 오류를 생성합니다.The preceding code generates the following error in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015:

    error C2280: '<unnamed-type-u>::<unnamed-type-u>(void)': attempting to reference a deleted function  
    note: compiler has generated '<unnamed-type-u>::<unnamed-type-u>' here  
    

    이 문제를 해결하려면 생성자 및/또는 소멸자의 정의를 제공하세요.To resolve this issue, provide your own definitions of the constructor and/or destructor.

    struct S {  
    // Provide a default constructor by adding an empty function body.  
    S() {}   
    };  
    
    union {  
    struct {  
    S s;  
    };  
    } u;  
    
  • 익명 구조체가 있는 공용 구조체Unions with anonymous structs

    공용 구조체에서 익명 구조체 멤버의 런타임 동작이 표준을 준수하도록 변경되었습니다.In order to conform with the standard, the runtime behavior has changed for members of anonymous structures in unions. 해당 공용 구조체가 생성될 때 공용 구조체의 익명 구조체 멤버에 대한 생성자가 더 이상 암시적으로 호출되지 않습니다.The constructor for anonymous structure members in a union is no longer implicitly called when such a union is created. 또한 공용 구조체가 범위를 벗어날 때 공용 구조체의 익명 구조체 멤버에 대한 소멸자가 더 이상 암시적으로 호출되지 않습니다.Also, the destructor for anonymous structure members in a union is no longer implicitly called when the union goes out of scope. 소멸자가 있는 명명된 구조체 S 멤버가 포함된 익명 구조체가 공용 구조체 U에 들어 있는 다음 코드를 고려하세요.Consider the following code, in which a union U contains an anonymous structure that contains a member which is a named structure S that has a destructor.

    #include <stdio.h>  
    struct S {  
        S() { printf("Creating S\n"); }  
        ~S(){ printf("Destroying S\n"); }  
    };  
    union U {  
        struct {  
        S s;  
    };  
        U() {}  
        ~U(){}  
    };  
    
    void f()  
    {  
        U u;  
        // Destructor implicitly called here.  
    }  
    
    int main()  
    {  
        f();  
    
        char s[1024];  
        printf("Press any key.\n");  
        gets_s(s);  
        return 0;  
    }  
    

    --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013에서 S에 대한 생성자는 공용 구조체가 생성될 때 호출되고 S에 대한 소멸자는 f 함수의 스택이 정리될 때 호출됩니다.In --- --- Visual Studio 2013의 Visual C++Visual C++ in Visual Studio 2013, the constructor for S is called when the union is created, and the destructor for S is called when the stack for function f is cleaned up. 그러나 --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015에서는 생성자와 소멸자가 호출되지 않습니다.But in --- --- Visual Studio 2015의 Visual C++Visual C++ in Visual Studio 2015, the constructor and destructor are not called. 컴파일러에서 이 동작 변경에 대해 경고를 표시합니다.The compiler gives a warning about this behavior change.

    warning C4587: 'U::s': behavior change: constructor is no longer implicitly calledwarning C4588: 'U::s': behavior change: destructor is no longer implicitly called  
    

    원래 동작을 복원하려면 익명 구조체에 이름을 지정합니다.To restore the original behavior, give the anonymous structure a name. 익명이 아닌 구조체의 런타임 동작은 컴파일러 버전과 관계없이 동일합니다.The runtime behavior of non-anonymous structures is the same, regardless of the compiler version.

    #include <stdio.h>  
    
    struct S {  
        S() { printf("Creating S.\n"); }  
        ~S() { printf("Destroying S\n"); }  
    };  
    union U {  
        struct {  
            S s;  
        } namedStruct;  
        U() {}  
        ~U() {}  
    };  
    
    void f()  
    {  
        U u;  
    }  
    
    int main()  
    {  
        f();  
    
        char s[1024];  
        printf("Press any key.\n");  
        gets_s(s);  
        return 0;  
    }  
    

    또는 생성자 및 소멸자 코드를 새 함수로 이동하고 공용 구조체에 대한 생성자 및 소멸자에서 이들 함수에 호출을 추가하세요.Alternatively, try moving the constructor and destructor code into new functions, and add calls to these functions from the constructor and destructor for the union.

    #include <stdio.h>  
    
    struct S {  
        void Create() { printf("Creating S.\n"); }  
        void Destroy() { printf("Destroying S\n"); }  
    };  
    union U {  
        struct {  
            S s;  
        };  
        U() { s.Create();  }  
        ~U() { s.Destroy(); }  
    };  
    
    void f()  
    {  
        U u;  
    }  
    
    int main()  
    {  
        f();  
    
    char s[1024];  
    printf("Press any key.\n");  
    gets_s(s);  
    return 0;  
    }  
    
  • 템플릿 확인Template resolution

    템플릿의 이름 확인에 대한 변경 내용이 있습니다.Changes have been made to name resolution for templates. C++에서 이름을 확인할 후보를 고려할 때 잠재적인 일치 항목으로 고려 중인 하나 이상의 이름에서 잘못된 템플릿 인스턴스화가 생성될 수 있습니다.In C++, when considering candidates for the resolution of a name, it can be the case that one or more names under consideration as potential matches produces an invalid template instantiation. 보통 이들 잘못된 인스턴스화 때문에 컴파일러 오류가 발생하지는 않습니다. 이 원칙을 SFINAE(Substitution Failure Is Not An Error)라고 합니다.These invalid instantiations do not normally cause compiler errors, a principle which is known as SFINAE (Substitution Failure Is Not An Error).

    현재 SFINAE에 따라 컴파일러가 클래스 템플릿의 특수화를 인스턴스화해야 하면 이 프로세스 중에 발생하는 오류는 컴파일러 오류입니다.Now, if SFINAE requires the compiler to instantiate the specialization of a class template, then any errors that occur during this process are compiler errors. 이전 버전에서는 컴파일러가 해당 오류를 무시합니다.In previous versions, the compiler would ignore such errors. 예를 들어, 다음 코드를 고려하세요.For example, consider the following code:

    #include <type_traits>  
    
    template<typename T>  
    struct S  
    {  
    S() = default;  
    S(const S&);  
    S(S&&);  
    
    template<typename U, typename = typename std::enable_if<std::is_base_of<T, U>::value>::type>  
    S(S<U>&&);  
    };  
    
    struct D;  
    
    void f1()  
    {  
    S<D> s1;  
        S<D> s2(s1);  
    }  
    
    struct B  
    {  
    };  
    
    struct D : public B  
    {  
    };  
    
    void f2()  
    {  
    S<D> s1;  
        S<D> s2(s1);  
    }  
    

    현재 컴파일러로 컴파일할 경우 다음 오류가 발생합니다.If you compile with the current compiler, you get the following error:

    type_traits(1110): error C2139: 'D': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_base_of'  
    ..\t331.cpp(14): note: see declaration of 'D'  
    ..\t331.cpp(10): note: see reference to class template instantiation 'std::is_base_of<T,U>' being compiled  
            with  
            [  
                T=D,  
                U=D  
            ]  
    

    이는 is_base_of의 첫 번째 호출 지점에서 'D' 클래스가 아직 정의되지 않았기 때문입니다.This is because at the point of the first invocation of the is_base_of the class 'D' has not yet been defined.

    이 경우 문제를 해결하려면 클래스가 정의될 때까지 이러한 형식 특성을 사용하지 마세요.In this case, the fix is not to use such type traits until the class has been defined. B 및 D의 정의를 코드 파일의 시작 부분으로 이동하면 오류가 해결됩니다.If you move the definitions of B and D to the beginning of the code file, the error is resolved. 정의가 헤더 파일에 있으면 헤더 파일의 include 문 순서를 확인하여 문제가 있는 템플릿이 사용되기 전에 클래스 정의가 컴파일되는지 확인합니다.If the definitions are in header files, check the order of the include statements for the header files to make sure that any class definitions are compiled before the problematic templates are used.

  • 복사 생성자Copy constructors

    --- --- Visual Studio 2013Visual Studio 2013 및 Visual Studio 2015에서 컴파일러는 클래스에 사용자 정의 이동 생성자가 있지만 사용자 정의 복사 생성자가 없을 경우 해당 클래스에 대한 복사 생성자를 생성합니다.In both --- --- Visual Studio 2013Visual Studio 2013 and Visual Studio 2015, the compiler generates a copy constructor for a class if that class has a user-defined move constructor but no user-defined copy constructor. Dev14에서는 생성된 복사 생성자가 "= delete"로 표시됩니다.In Dev14, this implicitly generated copy constructor is also marked "= delete".

업데이트 1의 규칙 향상Conformance Improvements in Update 1

  • 개인 가상 기본 클래스 및 간접 상속Private virtual base classes and indirect inheritance

    이전 버전의 컴파일러에서는 파생 클래스에서 간접적으로 파생된private virtual 기본 클래스의 멤버 함수를 호출할 수 있었습니다.Previous versions of the compiler allowed a derived class to call member functions of its indirectly-derivedprivate virtual base classes. 이 이전 동작은 올바르지 않으며 C++ 표준을 따르지 않습니다.This old behavior was incorrect and does not conform to the C++ standard. 컴파일러는 이러한 방식으로 작성된 코드를 더 이상 허용하지 않으며, 결과적으로 컴파일러 오류 C2280이 발생합니다.The compiler no longer accepts code written in this way and issues compiler error C2280 as a result.

    error C2280: 'void *S3::__delDtor(unsigned int)': attempting to reference a deleted function  
    

    예제(이전)Example (before)

    class base  
    {  
    protected:  
        base();  
        ~base();  
    };  
    
    class middle: private virtual base {};class top: public virtual middle {};  
    
    void destroy(top *p)  
    {  
        delete p;  //   
    }  
    

    예제(이후)Example (after)

    class base;  // as above  
    
    class middle: protected virtual base {};  
    class top: public virtual middle {};  
    
    void destroy(top *p)  
    {  
        delete p;  
    }  
    

    또는-or-

    class base;  // as above  
    
    class middle: private virtual base {};  
    class top: public virtual middle, private virtual bottom {};  
    
    void destroy(top *p)  
    {  
        delete p;  
    }  
    
  • 오버로드된 operator new 및 operator deleteOverloaded operator new and operator delete

    이전 버전의 컴파일러에서는 멤버가 아닌 operator new 및 멤버가 아닌 operator delete 를 정적으로 선언할 수 있었으며 전역 네임스페이스 이외의 네임스페이스에서 선언할 수 있었습니다.Previous versions of the compiler allowed non-member operator new and non-member operator delete to be declared static, and to be declared in namespaces other than the global namespace. 이 이전 동작은 프로그램에서 프로그래머가 의도한 new 또는 delete 연산자 구현을 호출하지 않아서 잘못된 자동 런타임 동작이 발생하는 위험을 초래했습니다.This old behavior created a risk that the program would not call the new or delete operator implementation that the programmer intended, resulting in silent bad runtime behavior. 컴파일러는 이러한 방식으로 작성된 코드를 더 이상 허용하지 않으며, 대신 컴파일러 오류 C2323이 발생합니다.The compiler no longer accepts code written in this way and issues compiler error C2323 instead.

    error C2323: 'operator new': non-member operator new or delete functions may not be declared static or in a namespace other than the global namespace.  
    

    예제(이전)Example (before)

    static inline void * __cdecl operator new(size_t cb, const std::nothrow_t&)  // error C2323  
    

    예제(이후)Example (after)

    void * __cdecl operator new(size_t cb, const std::nothrow_t&)  // removed 'static inline'  
    

    또한 컴파일러가 특정 진단을 제공하지는 않지만, 인라인 operator new는 잘못된 형식으로 간주됩니다.Additionally, although the compiler doesn't give a specific diagnostic, inline operator new is considered ill-formed.

  • 비클래스 형식에서 'operator type()'(사용자 정의 변환) 호출Calling 'operator type()' (user-defined conversion) on non-class types

    이전 버전의 컴파일러에서는 'operator type()'을 자동으로 무시하면서 비클래스 형식에서 호출할 수 있었습니다.Previous versions of the compiler allowed 'operator type()' to be called on non-class types while silently ignoring it. 이 이전 동작으로 잘못된 코드가 자동으로 생성되어 예기치 않은 런타임 동작이 발생하는 위험이 초래되었습니다.This old behavior created a risk of silent bad code generation, resulting in unpredictable runtime behavior. 컴파일러는 이러한 방식으로 작성된 코드를 더 이상 허용하지 않으며, 대신 컴파일러 오류 C2228이 발생합니다.The compiler no longer accepts code written in this way and issues compiler error C2228 instead.

    error C2228: left of '.operator type' must have class/struct/union  
    

    예제(이전)Example (before)

    typedef int index_t;  
    
    void bounds_check(index_t index);  
    
    void login(int column)  
    {  
        bounds_check(column.operator index_t());  // error C2228  
    }  
    

    예제(이후)Example (after)

    typedef int index_t;  
    
    void bounds_check(index_t index);  
    
    void login(int column)  
    {  
        bounds_check(column);  // removed cast to 'index_t', 'index_t' is an alias of 'int'  
    }  
    
  • 상세 형식 지정자의 중복 typenameRedundant typename in elaborated type specifiers

    이전 버전의 컴파일러에서는 상세 형식 지정자에 typename 이 허용되었습니다. 이러한 방식으로 작성된 코드는 의미 체계가 잘못되었습니다.Previous versions of the compiler allowed typename in an elaborated type specifiers; code written in this way is semantically incorrect. 컴파일러는 이러한 방식으로 작성된 코드를 더 이상 허용하지 않으며, 대신 컴파일러 오류 C3406이 발생합니다.The compiler no longer accepts code written in this way and issues compiler error C3406 instead.

    error C3406: 'typename' cannot be used in an elaborated type specifier  
    

    예제(이전)Example (before)

    template <typename class T>  
    class container;  
    

    예제(이후)Example (after)

    template <class T>  // alternatively, could be 'template <typename T>'; 'typename' is not elaborating a type specifier in this case  
    class container;  
    
  • 이니셜라이저 목록에서 배열의 형식 추론Type deduction of arrays from an initializer list

    이전 버전의 컴파일러는 이니셜라이저 목록에서 배열의 형식 추론을 지원하지 않았습니다.Previous versions of the compiler did not support type deduction of arrays from an initializer list. 이제 컴파일러가 이러한 형태의 형식 추론을 지원합니다. 결과적으로 이니셜라이저 목록을 사용한 함수 템플릿 호출은 이제 모호하거나 이전 버전의 컴파일러와 다른 오버로드가 선택될 수 있습니다.The compiler now supports this form of type deduction and, as a result, calls to function templates using initializer lists might now be ambiguous or a different overload might be chosen than in previous versions of the compiler. 이러한 문제를 해결하려면 이제 프로그램에서 프로그래머가 의도한 오버로드를 명시적으로 지정해야 합니다.To resolve these issues, the program must now explicitly specify the overload that the programmer intended.

    이 새로운 동작으로 오버로드 확인에서 기록 후보와 똑같이 우수한 추가 후보를 고려하게 되는 경우, 호출이 모호해지며 결과적으로 컴파일러에서 컴파일러 오류 C2668이 발생합니다.When this new behavior causes overload resolution to consider an additional candidate that is equally as good as the historic candidate, the call becomes ambiguous and the compiler issues compiler error C2668 as a result.

    error C2668: 'function' : ambiguous call to overloaded function.  
    

    예제 1: 오버로드된 함수에 대한 호출이 모호합니다(이전).Example 1: Ambiguous call to overloaded function (before)

    // In previous versions of the compiler, code written in this way would unambiguously call f(int, Args...)  
    template <typename... Args>  
    void f(int, Args...);  //   
    
    template <int N, typename... Args>  
    void f(const int (&)[N], Args...);  
    
    int main()  
    {  
        // The compiler now considers this call ambiguous, and issues a compiler error  
        f({3});  error C2668: 'f' ambiguous call to overloaded function  
    }  
    

    예제 1: 오버로드된 함수에 대한 호출이 모호합니다(이후).Example 1: ambiguous call to overloaded function (after)

    template <typename... Args>  
    void f(int, Args...);  //   
    
    template <int N, typename... Args>  
    void f(const int (&)[N], Args...);  
    
    int main()  
    {  
        // To call f(int, Args...) when there is just one expression in the initializer list, remove the braces from it.  
        f(3);  
    }  
    

    이 새로운 동작으로 오버로드 확인에서 기록 후보보다 더 일치되는 추가 후보를 고려하게 되는 경우, 호출이 새 후보로 명확하게 확인되므로 프로그래머가 의도한 것과 다른 프로그램 동작 변경을 초래할 수 있습니다.When this new behavior causes overload resolution to consider an additional candidate that is a better match than the historic candidate, the call resolves unambiguously to the new candidate, causing a change in program behavior that is probably different than the programmer intended.

    예제 2: 오버로드 확인의 변경(이전)Example 2: change in overload resolution (before)

    // In previous versions of the compiler, code written in this way would unambiguously call f(S, Args...)  
    struct S  
    {  
        int i;  
        int j;  
    };  
    
    template <typename... Args>  
    void f(S, Args...);  
    
    template <int N, typename... Args>  
    void f(const int *&)[N], Args...);  
    
    int main()  
    {  
        // The compiler now resolves this call to f(const int (&)[N], Args...) instead  
        f({1, 2});  
    }  
    

    예제 2: 오버로드 확인의 변경(이후)Example 2: change in overload resolution (after)

    struct S;  // as before  
    
    template <typename... Args>  
    void f(S, Args...);  
    
    template <int N, typename... Args>  
    void f(const int *&)[N], Args...);  
    
    int main()  
    {  
        // To call f(S, Args...), perform an explicit cast to S on the initializer list.  
        f(S{1, 2});  
    }  
    
  • switch 문 경고의 복원Restoration of switch statement warnings

    이전 버전의 컴파일러에서는 switch 문과 관련된 기존 경고를 제거했습니다. 이제 이러한 경고가 복원되었습니다.A Previous version of the compiler removed previously-existing warnings related to switch statements; these warnings have now been restored. 이제 컴파일러에서 복원된 경고가 발생합니다. 이제 특정 사례(기본 사례 포함)와 관련된 경고가 switch 문의 마지막 줄 대신, 잘못된 사례가 포함된 줄에서 발생합니다.The compiler now issues the restored warnings, and warnings related to specific cases (including the default case) are now issued on the line containing the offending case, rather than on the last line of the switch statement. 이제 과거와는 다른 줄에서 해당 경고가 발생하므로 이전에 #pragma warning(disable:####) 을 사용하면 표시되지 않았던 경고가 더 이상 의도한 대로 숨겨지지 않을 수 있습니다.As a result of now issuing those warnings on different lines than in the past, warnings previously suppressed by using #pragma warning(disable:####) may no longer be suppressed as intended. 이러한 경고를 의도한 대로 표시하지 않으려면 #pragma warning(disable:####) 지시문을 잠재적으로 잘못된 첫 번째 사례 위의 줄로 이동해야 할 수 있습니다.To suppress these warnings as intended, it might be necessary to move the #pragma warning(disable:####) directive to a line above the first potentially-offending case. 다음은 복원된 경고입니다.The following are the restored warnings.

    warning C4060: switch statement contains no 'case' or 'default' labels  
    
    warning C4061: enumerator 'bit1' in switch of enum 'flags' is not explicitly handled by a case label  
    
    warning C4062: enumerator 'bit1' in switch of enum 'flags' is not handled  
    
    warning C4063: case 'bit32' is not a valid value for switch of enum 'flags'  
    
    warning C4064: switch of incomplete enum 'flags'  
    
    warning C4065: switch statement contains 'default' but no 'case' labels  
    
    warning C4808: case 'value' is not a valid value for switch condition of type 'bool'  
    
    Warning C4809: switch statement has redundant 'default' label; all possible 'case' labels are given  
    

    C4063의 예제(이전)Example of C4063 (before)

    class settings  
    {  
    public:  
        enum flags  
        {  
            bit0 = 0x1,  
            bit1 = 0x2,  
            ...  
        };  
        ...  
    };  
    
    int main()  
    {  
        auto val = settings::bit1;  
    
        switch (val)  
        {  
        case settings::bit0:  
            break;  
    
        case settings::bit1:  
            break;  
    
        case settings::bit0 | settings::bit1:  // warning C4063  
            break;  
        }  
    };  
    

    C4063의 예제(이후)Example of C4063 (after)

    class settings {...};  // as above  
    
    int main()  
    {  
        // since C++11, use std::underlying_type to determine the underlying type of an enum  
        typedef std::underlying_type<settings::flags>::type flags_t;  
    
        auto val = settings::bit1;  
    
        switch (static_cast<flags_t>(val))  
        {  
        case settings::bit0:  
            break;  
    
        case settings::bit1:  
            break;  
    
        case settings::bit0 | settings::bit1:  // ok  
            break;  
        }  
    };  
    

    복원된 다른 경고의 예는 해당 설명서에 제공됩니다.Examples of the other restored warnings are provided in their documentation.

  • #include: 경로 이름에 부모 디렉터리 지정자 '..' 사용 (/Wall /WX에만 영향을 줌)#include: use of parent-directory specifier '..' in pathname (only affects /Wall /WX)

    이전 버전의 컴파일러에서는Previous versions of the compiler did not detect the use of the parent-directory specifier '..' #include 지시문의 경로 이름에서 부모 디렉터리 지정자('..')의 사용을 검색하지 못했습니다.in the pathname of #include directives. 이러한 방식으로 작성된 코드는 일반적으로 프로젝트 상대 경로를 부정확하게 사용하여 프로젝트의 외부에 존재하는 헤더를 포함합니다.Code written in this way is usually intended to include headers that exist outside of the project by incorrectly using project-relative paths. 이 이전 동작은 프로그램이 프로그래머가 의도한 것과 다른 소스 파일을 포함하여 컴파일되거나 이러한 상대 경로가 다른 빌드 환경으로 이식되지 않는 위험을 초래했습니다.This old behavior created a risk that the program could be compiled by including a different source file than the programmer intended, or that these relative paths would not be portable to other build environments. 이제 컴파일러는 이러한 방식으로 작성된 코드를 검색하여 프로그래머에게 알립니다. 그리고 사용하도록 설정된 경우 선택적으로 컴파일러 경고 C4464가 발생합니다.The compiler now detects and notifies the programmer of code written in this way and issues an optional compiler warning C4464, if enabled.

    warning C4464: relative include path contains '..'  
    

    예제(이전)Example (before)

    #include "..\headers\C4426.h"  // emits warning C4464  
    

    예제(이후)Example (after)

    #include "C4426.h"  // add absolute path to 'headers\' to your project's include directories  
    

    또한 컴파일러가 특정 진단을 제공하지는 않지만, 프로젝트의 Include 디렉터리를 지정하는 데 부모 디렉터리 지정자("..")를 사용하지 않는 것이 좋습니다.Additionally, although the compiler does not give a specific diagnostic, we also recommend that the parent-directory specifier ".." should note be used to specify your project's include directories.

  • #pragma optimize()에서 헤더 파일의 끝을 넘어 확장 (/Wall /WX에만 영향을 줌)#pragma optimize() extends past end of header file (only affects /Wall /WX)

    이전 버전의 컴파일러에서는 변환 단위 내에 포함된 헤더 파일을 이스케이프하는 최적화 플래그 설정에 대한 변경 내용을 검색하지 못했습니다.Previous versions of the compiler did not detect changes to optimization flag settings that escape a header file included within a translation unit. 이제 컴파일러는 이러한 방식으로 작성된 코드를 검색하여 프로그래머에게 알립니다. 그리고 사용하도록 설정된 경우 잘못된 #include의 위치에서 선택적으로 컴파일러 경고 C4426이 발생합니다.The compiler now detects and notifies the programmer of code written in this way and issues an optional compiler warning C4426 at the location of the offending #include, if enabled. 이 경고는 변경 내용이 명령줄 인수에 의해 컴파일러에 설정된 최적화 플래그와 충돌하는 경우에만 발생합니다.This warning is only issued if the changes conflict with the optimization flags set by command-line arguments to the compiler.

    warning C4426: optimization flags changed after including header, may be due to #pragma optimize()  
    

    예제(이전)Example (before)

    // C4426.h  
    #pragma optimize("g", off)  
    ...  
    // C4426.h ends  
    
    // C4426.cpp  
    #include "C4426.h"  // warning C4426  
    

    예제(이후)Example (after)

    // C4426.h  
    #pragma optimize("g", off)  
    ...  
    #pragma optimize("", on)  // restores optimization flags set via command-line arguments  
    // C4426.h ends  
    
    // C4426.cpp  
    #include "C4426.h"  
    
  • #pragma warning(push)#pragma warning(pop) (/Wall /WX에만 영향을 줌)Mismatched #pragma warning(push) and #pragma warning(pop) (only affects /Wall /WX)

    이전 버전의 컴파일러는 다른 소스 파일에서 #pragma warning(push) 상태 변경이 #pragma warning(pop) 상태 변경과 쌍을 이루는 것(의도되는 경우가 드묾)을 검색하지 못했습니다.Previous versions of the compiler did not detect #pragma warning(push) state changes being paired with #pragma warning(pop) state changes in a different source file, which is rarely intended. 이 이전 동작으로 프로그램이 프로그래머가 의도한 것과 다르게 설정된 경고 집합으로 컴파일되어 잘못된 자동 런타임 동작이 발생하는 위험이 초래됩니다.This old behavior created a risk that the program would be compiled with a different set of warnings enabled than the programmer intended, possibly resulting in silent bad runtime behavior. 이제 컴파일러는 이러한 방식으로 작성된 코드를 검색하여 프로그래머에게 알립니다. 그리고 사용하도록 설정된 경우 일치하는 #pragma warning(pop)의 위치에서 선택적으로 컴파일러 경고 C5031이 발생합니다.The compiler now detects and notifies the programmer of code written in this way and issues an optional compiler warning C5031 at the location of the matching #pragma warning(pop), if enabled. 이 경고에는 해당 #pragma warning(push)의 위치를 참조하는 참고가 포함되어 있습니다.This warning includes a note referencing the location of the corresponding #pragma warning(push).

    warning C5031: #pragma warning(pop): likely mismatch, popping warning state pushed in different file  
    

    예제(이전)Example (before)

    // C5031_part1.h  
    #pragma warning(push)  
    #pragma warning(disable:####)  
    ...  
    // C5031_part1.h ends without #pragma warning(pop)  
    
    // C5031_part2.h  
    ...  
    #pragma warning(pop)  // pops a warning state not pushed in this source file   
    ...  
    // C5031_part1.h ends  
    
    // C5031.cpp  
    #include "C5031_part1.h" // leaves #pragma warning(push) 'dangling'  
    ...  
    #include "C5031_part2.h" // matches 'dangling' #pragma warning(push), resulting in warning C5031  
    ...  
    

    예제(이후)Example (after)

    // C5031_part1.h  
    #pragma warning(push)  
    #pragma warning(disable:####)  
    ...  
    #pragma warning(pop)  // pops the warning state pushed in this source file  
    // C5031_part1.h ends without #pragma warning(pop)  
    
    // C5031_part2.h  
    #pragma warning(push)  // pushes the warning state pushed in this source file  
    #pragma warning(disable:####)  
    ...  
    #pragma warning(pop)  
    // C5031_part1.h ends  
    
    // C5031.cpp  
    #include "C5031_part1.h" // #pragma warning state changes are self-contained and independent of other source files or their #include order.  
    ...  
    #include "C5031_part2.h"  
    ...  
    

    드물긴 하지만 의도적으로 이러한 코드를 작성하는 경우가 있습니다.Though uncommon, code written in this way is sometimes intentional. 이러한 방식으로 작성된 코드는 #include 순서의 변경에 민감합니다. 가능한 경우 소스 코드 파일에서 자동으로 포함된 방식으로 경고 상태를 관리하는 것이 좋습니다.Code written in this way is sensitive to changes in #include order; when possible, we recommend that source code files manage warning state in a self-contained way.

  • #pragma warning(push) 불일치 (/Wall /WX에만 영향을 줌)Unmatched #pragma warning(push) (only affects /Wall /WX)

    이전 버전의 컴파일러는 변환 단위의 끝에서 #pragma warning(push) 상태 변경 불일치를 검색하지 못했습니다.Previous versions of the compiler did not detect unmatched #pragma warning(push) state changes at the end of a translation unit. 이제 컴파일러는 이러한 방식으로 작성된 코드를 검색하여 프로그래머에게 알립니다. 그리고 사용하도록 설정된 경우 일치하지 않는 #pragma warning(push)의 위치에서 선택적으로 컴파일러 경고 C5032가 발생합니다.The compiler now detects and notifies the programmer of code written in this way and issues an optional compiler warning C5032 at the location of the unmatched #pragma warning(push), if enabled. 이 경고는 변환 단위에 컴파일 오류가 없는 경우에만 발생합니다.This warning is only issued if there are no compilation errors in the translation unit.

    warning C5032: detected #pragma warning(push) with no corresponding #pragma warning(pop)  
    

    예제(이전)Example (before)

    // C5032.h  
    #pragma warning(push)  
    #pragma warning(disable:####)  
    ...  
    // C5032.h ends without #pragma warning(pop)  
    
    // C5032.cpp  
    #include "C5032.h"  
    ...  
    // C5032.cpp ends -- the translation unit is completed without #pragma warning(pop), resulting in warning C5032 on line 1 of C5032.h  
    

    예제(이후)Example (after)

    // C5032.h  
    #pragma warning(push)  
    #pragma warning(disable:####)  
    ...  
    #pragma warning(pop) // matches #pragma warning (push) on line 1  
    // C5032.h ends  
    
    // C5032.cpp  
    #include "C5032.h"  
    ...  
    // C5032.cpp ends -- the translation unit is completed without unmatched #pragma warning(push)  
    
  • 개선된 #pragma warning 상태 추적의 결과로 추가 경고가 발생할 수 있습니다.Additional warnings might be issued as a result of improved #pragma warning state tracking

    이전 버전의 컴파일러는 의도된 모든 경고를 발생시키기에는 불충분한 수준으로 #pragma warning 상태 변경을 추적했습니다.Previous versions of the compiler tracked #pragma warning state changes insufficiently well to issue all intended warnings. 이 동작으로 프로그래머가 의도한 것과 다른 상황에서 특정 경고가 효과적으로 표시되지 않는 위험이 초래됩니다.This behavior created a risk that certain warnings would be effectively suppressed in circumstances different than the programmer intended. 이제 컴파일러는 #pragma warning 상태(특히 템플릿 내부의 #pragma warning 상태 변경과 관련된 내용)를 더욱 강력하게 추적하며, 선택적으로 새로운 경고 C5031 및 C5032가 발생합니다. 이러한 경고는 프로그래머가 #pragma warning(push)#pragma warning(pop)의 의도하지 않은 사용을 찾는 데 도움이 됩니다.The compiler now tracks #pragma warning state more robustly -- especially related to #pragma warning state changes inside of templates -- and optionally issues new warnings C5031 and C5032 which are intended to help the programmer locate unintended uses of #pragma warning(push) and #pragma warning(pop).

    개선된 #pragma warning 상태 변경 추적의 결과로, 이전에 제대로 표시되지 않은 경고 또는 이전에 잘못 진단된 문제와 관련된 경고가 이제 발생할 수 있습니다.As a result of improved #pragma warning state change tracking, warnings formerly incorrectly suppressed or warnings related to issues formerly misdiagnosed might now be issued.

  • 접근할 수 없는 코드의 개선된 IDImproved identification of unreachable code

    C++ 표준 라이브러리의 변경 및 이전 버전의 컴파일러에 비해 향상된 인라인 함수 호출 기능을 통해 컴파일러가 이제 특정 코드에 접근할 수 없음을 증명할 수 있습니다.C++ Standard Library changes and improved ability to inline function calls over previous versions of the compiler might allow the compiler to prove that certain code is now unreachable. 이 새로운 동작으로 경고 C4720의 인스턴스가 새로 그리고 더욱 자주 발생할 수 있습니다.This new behavior can result in new and more-frequently issued instances of warning C4720.

    warning C4720: unreachable code  
    

    최적화 프로세스에서 더 많은 함수 호출을 인라인하거나 중복 코드를 제거하거나 특정 코드에 접근할 수 없는지 확인할 수 있도록 하므로, 이 경고는 대개 최적화를 사용하면서 컴파일할 경우에만 발생할 수 있습니다.In many cases, this warning might only be issued when compiling with optimizations enabled, since optimizations may inline more function calls, eliminate redundant code, or otherwise make it possible to determine that certain code is unreachable. 경고 C4720의 새 인스턴스가 특히 std::find의 사용과 관련하여 try/catch 블록에서 자주 발생했음을 관찰했습니다.We have observed that new instances of warning C4720 have frequently occurred in try/catch blocks, especially in relation to use of std::find.

    예제(이전)Example (before)

    try   
    {   
        auto iter = std::find(v.begin(), v.end(), 5);   
    }   
    catch(...)   
    {   
        do_something();  // ok   
    }  
    

    예제(이후)Example (after)

    try   
    {   
        auto iter = std::find(v.begin(), v.end(), 5);   
    }   
    catch(...)   
    {   
        do_something();  // warning C4702: unreachable code  
    }  
    

업데이트 2의 규칙 향상Conformance Improvements in Update 2

  • SFINAE 식에 대한 부분 지원으로 인해 추가 경고 및 오류가 발생할 수 있습니다.Additional warnings and errors might be issued as a result of partial support for expression SFINAE

    이전 버전의 컴파일러는 SFINAE 식에 대한 지원 부족으로 decltype 지정자 내의 특정 유형의 식을 구문 분석하지 않았습니다.Previous versions of the compiler did not parse certain kinds of expressions inside decltype specifiers due to lack of support for expression SFINAE. 이 이전 동작은 올바르지 않으며 C++ 표준을 따르지 않습니다.This old behavior was incorrect and does not conform to the C++ standard. 지속적인 규칙 향상으로 인해 이제 컴파일러는 이러한 식을 구문 분석하고 SFINAE 식에 대한 부분 지원을 합니다.The compiler now parses these expressions and has partial support for expression SFINAE due to ongoing conformance improvements. 결과적으로 이제 컴파일러는 이전 버전의 컴파일러가 구문 분석하지 않았던 식에서 경고 및 오류를 발생합니다.As a result, the compiler now issues warnings and errors found in expressions that previous versions of the compiler did not parse.

    이 새로운 동작이 아직 선언되지 않은 형식을 포함하는 decltype 식을 구문 분석할 때, 컴파일러는 결과적으로 오류 C2039를 발생합니다.When this new behavior parses a decltype expression that includes a type that has not yet been declared, the compiler issues compiler error C2039 as a result.

    error C2039: 'type': is not a member of '`global namespace''  
    

    예제 1: 선언되지 않은 형식 사용(이전)Example 1: use of an undeclared type (before)

    struct s1  
    {  
      template <typename T>  
      auto f() -> decltype(s2<T>::type::f());  // error C2039  
    
      template<typename>  
      struct s2 {};  
    }  
    

    예제 1(이후)Example 1 (after)

    struct s1  
    {  
      template <typename>  // forward declare s2struct s2;  
    
      template <typename T>  
      auto f() -> decltype(s2<T>::type::f());  
    
      template<typename>  
      struct s2 {};  
    }  
    

    이 새로운 동작이 종속 이름이 형식임을 지정하기 위해 필요한 typename 키워드 사용이 누락된 decltype 식을 구문 분석할 때 컴파일러는 컴파일러 오류 C2923과 함께 컴파일러 경고 C4346을 발생합니다.When this new behavior parses a decltype expression that is missing a necessary use of the typename keyword to specify that a dependent name is a type, the compiler issues compiler warning C4346 together with compiler error C2923.

    warning C4346: 'S2<T>::Type': dependent name is not a type  
    
    error C2923: 's1': 'S2<T>::Type' is not a valid template type argument for parameter 'T'  
    

    예제 2: 종속 이름이 형식이 아님(이전)Example 2: dependent name is not a type (before)

    template <typename T>  
    struct s1  
    {  
      typedef T type;  
    };  
    
    template <typename T>  
    struct s2  
    {  
      typedef T type;  
    };  
    
    template <typename T>  
    T declval();  
    
    struct s  
    {  
      template <typename T>  
      auto f(T t) -> decltype(t(declval<S1<S2<T>::type>::type>()));  // warning C4346, error C2923  
    };  
    

    예제 2(이후)Example 2 (after)

    template <typename T> struct s1 {...};  // as above  
    template <typename T> struct s2 {...};  // as above  
    
    template <typename T>  
    T declval();  
    
    struct s  
    {  
      template <typename T>  
      auto f(T t) -> decltype(t(declval<S1<typename S2<T>::type>::type>()));  
    };  
    
  • volatile 멤버 변수가 암시적으로 정의된 생성자와 대입 연산자를 막음volatile member variables prevent implicitly defined constructors and assignment operators

    이전 버전의 컴파일러는 volatile 멤버 변수가 있는 클래스가 기본 복사/이동 생성자 및 기본 복사 대입 연산자를 자동으로 생성하도록 허용했습니다.Previous versions of the compiler allowed a class that has volatile member variables to have default copy/move constructors and default copy/move assignment operators automatically generated. 이 이전 동작은 올바르지 않으며 C++ 표준을 따르지 않습니다.This old behavior was incorrect and does not conform to the C++ standard. 이제 컴파일러는 volatile 멤버 변수가 있는 클래스는 특수한 생성자 및 대입 연산자가 있는 것으로 간주하여 이러한 연산자의 기본 구현이 자동으로 생성되는 것을 막습니다.The compiler now considers a class that has volatile member variables to have non-trivial construction and assignment operators which prevents default implementations of these operators from being automatically generated. 이러한 클래스가 공용 구조체(또는 클래스 내의 익명 공용 구조체)의 멤버이면 공용 구조체(또는 익명 공용 구조체를 포함하는 클래스)의 복사/이동 생성자 및 복사/이동 대입 연산자는 삭제된 것으로 암시적으로 정의됩니다.When such a class is a member of a union (or an anonymous union inside of a class), the copy/move constructors and copy/move assignment operators of the union (or the class containing the unonymous union) will be implicitly defined as deleted. 명시적으로 정의하지 않고 공용 구조체(또는 익명 공용 구조체를 포함하는 클래스)를 만들거나 복사하려 하면 오류가 발생하며 컴파일러에서 결과적으로 컴파일러 오류 C2280을 발생합니다.Attempting to construct or copy the union (or class containing the anonymous union) without explicitly defining them is an error and the compiler issues compiler error C2280 as a result.

    error C2280: 'B::B(const B &)': attempting to reference a deleted function  
    

    예제(이전)Example (before)

    struct A  
    {  
      volatile int i;  
      volatile int j;  
    };  
    
    extern A* pa;  
    
    struct B  
    {  
      union  
      {  
        A a;  
        int i;  
      };  
    };  
    
    B b1 {*pa};  
    B b2 (b1);  // error C2280  
    

    예제(이후)Example (after)

    struct A  
    {  
      int i;int j;  
    };  
    
    extern volatile A* pa;  
    
    A getA()  // returns an A instance copied from contents of pa  
    {  
      A a;  
      a.i = pa->i;  
      a.j = pa->j;  
      return a;  
    }  
    
    struct B;  // as above  
    
    B b1 {GetA()};  
    B b2 (b1);  // error C2280  
    
  • 정적 멤버 함수는 cv 한정자를 지원하지 않습니다.Static member functions do not support cv-qualifiers.

    이전 버전의 Visual C++ 2015는 정적 멤버 함수에 cv 한정자가 포함되는 것을 허용했습니다.Previous versions of Visual C++ 2015 allowed static member functions to have cv-qualifiers. 이 동작은 Visual C++ 2015 및 Visual C++ 2015 업데이트 1에서의 문제 재발로 인한 것입니다. Visual C++ 2013 및 이전 버전의 Visual C++는 이런 식으로 작성된 코드를 거부합니다.This behavior is due to a regression in Visual C++ 2015 and Visual C++ 2015 Update 1; Visual C++ 2013 and previous versions of Visual C++ reject code written in this way. Visual C++ 2015 및 Visual C++ 2015 업데이트 1의 동작은 잘못되었으며 C++ 표준과 일치하지 않습니다.The behavior of Visual C++ 2015 and Visual C++ 2015 Update 1 is incorrect and does not conform to the C++ standard. Visual Studio 2015 업데이트 2는 이런 식으로 작성된 코드를 거부하며 대신 컴파일러 오류 C2511을 발생합니다.Visual Studio 2015 Update 2 rejects code written in this way and issues compiler error C2511 instead.

    error C2511: 'void A::func(void) const': overloaded member function not found in 'A'  
    

    예제(이전)Example (before)

    struct A  
    {  
      static void func();  
    };  
    
    void A::func() const {}  // C2511  
    

    예제(이후)Example (after)

    struct A  
    {  
      static void func();  
    };  
    
    void A::func() {}  // removed const  
    
  • 열거형의 정방향 선언은 WinRT 코드에서 허용되지 않습니다(/ZW만 영향을 줌).Forward declaration of enum is not allowed in WinRT code (affects /ZW only)

    WinRT(Windows 런타임)에 대해 컴파일된 코드는 enum 형식이 정방향 선언되는 것을 허용하지 않습니다. /clr 컴파일러 스위치를 사용하여 관리되는 C++ 코드가 .Net Framework에 대해 컴파일되는 경우와 비슷합니다.Code compiled for the Windows Runtime (WinRT) doesn't allow enum types to be forward declared, similarly to when managed C++ code is compiled for the .Net Framework using the /clr compiler switch. 이 동작은 열거형의 크기를 항상 알 수 있으며 WinRT 형식 시스템에 올바르게 프로젝션될 수 있음을 확인합니다.This behavior is ensures that the size of an enumeration is always known and can be correctly projected to the WinRT type system. 컴파일러는 이러한 방식으로 작성된 코드를 거부하고 컴파일러 오류 C3197과 함께 컴파일러 오류 C2599를 발생합니다.The compiler rejects code written in this way and issues compiler error C2599 together with compiler error C3197.

    error C2599: 'CustomEnum': the forward declaration of a WinRT enum is not allowed  
    
    error C3197: 'public': can only be used in definitions  
    

    예제(이전)Example (before)

    namespace A {  
      public enum class CustomEnum: int32;  // forward declaration; error C2599, error C3197  
    }  
    
    namespace A {  
      public enum class CustomEnum: int32  
      {  
        Value1  
      };  
    }  
    
    public ref class Component sealed  
    {  
    public:  
      CustomEnum f()  
      {  
        return CustomEnum::Value1;  
      }  
    };  
    

    예제(이후)Example (after)

              // forward declaration of CustomEnum removed  
    
    namespace A {  
      public enum class CustomEnum: int32  
      {  
        Value1  
      };  
    }  
    
    public ref class Component sealed  
    {  
    public:  
      CustomEnum f()  
      {  
        return CustomEnum::Value1;  
      }  
    };  
    
  • 오버로드된 멤버가 아닌 연산자 new 및 연산자 delete는 인라인으로 선언할 수 없습니다(수준 1(/ W1)이 기본적으로 설정되어 있음).Overloaded non-member operator new and operator delete may not be declared inline (Level 1 (/W1) on-by-default)

    이전 버전의 컴파일러는 멤버가 아닌 연산자 new 및 연산자 delete 함수가 인라인으로 선언될 때 경고를 발생하지 않습니다.Previous versions of the compiler do not issue a warning when non-member operator new and operator delete functions are declared inline. 이 방식으로 작성된 코드는 형식이 잘못되었으며(진단이 필요하지 않음) 진단하기 힘들 수 있는 일치하지 않는 new 및 delete 연산자로 인해 특히 크기가 지정된 할당 해제와 함께 사용 시 메모리 문제를 일으킬 수 있습니다.Code written in this way is ill-formed (no diagnostic required) and can cause memory issues resulting from mismatched new and delete operators (especially when used together with sized deallocation) that can be difficult to diagnose. 이제 컴파일러는 이런 식으로 작성된 코드를 식별하기 위해 경고 C4595를 발생합니다.The compiler now issues compiler warning C4595 to help identify code written in this way.

    warning C4595: 'operator new': non-member operator new or delete functions may not be declared inline  
    

    예제(이전)Example (before)

              inline void* operator new(size_t sz)  // warning C4595  
    {  
      ...  
    }  
    

    예제(이후)Example (after)

              void* operator new(size_t sz)  // removed inline  
    {  
      ...  
    }  
    

    이러한 방식으로 작성된 코드를 수정하려면 연산자 정의를 헤더 파일에서 해당하는 소스 파일로 이동해야 합니다.Fixing code that's written in this way might require that the operator definitions be moved out of a header file and into a corresponding source file.

업데이트 3의 규칙 향상Conformance Improvements in Update 3

  • 이제 std::is_convertable이 자체 할당을 검색함(표준 라이브러리)std::is_convertable now detects self-assignment (standard library)

    이전 버전의 std::is_convertable 형식 특성은 복사 생성자가 삭제되거나 private인 경우 클래스 형식의 자체 할당을 제대로 검색하지 못했습니다.Previous versions of the std::is_convertable type-trait did not correctly detect self-assignment of a class type when its copy constructor is deleted or private. 이제 복사 생성자가 삭제되거나 private인 클래스 형식에 적용할 때 std::is_convertable<>::valuefalse로 올바르게 설정됩니다.Now, std::is_convertable<>::value is correctly set to false when applied to a class type with a deleted or private copy constructor.

    이 변경과 관련된 컴파일러 진단은 없습니다.There is no compiler diagnostic associated with this change.

    예제Example

    #include <type_traits>  
    
    class X1  
    {  
    public:  
        X1(const X1&) = delete;  
    };  
    
    class X2  
    {  
    private:  
        X2(const X2&);  
    };  
    
    static_assert(std::is_convertible<X1&, X1>::value, "BOOM");static_assert(std::is_convertible<X2&, X2>::value, "BOOM");  
    

    이전 버전의 Visual C++에서는 std::is_convertable<>::valuetrue로 잘못 설정되었기 때문에 이 예제의 맨 아래에 있는 정적 어설션이 성공합니다.In previous versions of Visual C++, the static assertions at the bottom of this example pass because std::is_convertable<>::value was incorrectly set to true. 이제 std::is_convertable<>::valuefalse로 올바르게 설정되므로 정적 어설션이 실패합니다.Now, std::is_convertable<>::value is correctly set to false, causing the static assertions to fail.

  • 기본값으로 설정되었거나 삭제된 trivial 복사 및 이동 생성자가 액세스 지정자를 따름Defaulted or deleted trivial copy and move constructors respect access specifiers

    이전 버전의 컴파일러에서는 호출을 허용하기 전에 기본값으로 설정되었거나 삭제된 trivial 복사 및 이동 생성자의 액세스 지정자를 확인하지 않았습니다.Previous versions of the compiler did not check the access specifier of defaulted or deleted trivial copy and move constructors before allowing them to be called. 이 이전 동작은 올바르지 않으며 C++ 표준을 따르지 않습니다.This old behavior was incorrect and does not conform to the C++ standard. 경우에 따라 이 이전 동작으로 잘못된 코드가 자동으로 생성되어 예기치 않은 런타임 동작이 발생하는 위험이 초래되었습니다.In some cases, this old behavior created a risk of silent bad code generation, resulting in unpredictable runtime behavior. 이제 컴파일러에서 기본값으로 설정되었거나 삭제된 trivial 복사 및 이동 생성자의 액세스 지정자를 검사하여 호출 가능 여부를 확인하고, 호출할 수 없는 경우 결과로 컴파일러 경고 C2248을 실행합니다.The compiler now checks the access specifier of defaulted or deleted trivial copy and move constructors to determine whether it can be called, and if not, issues compiler warning C2248 as a result.

    error C2248: 'S::S' cannot access private member declared in class 'S'  
    

    예제(이전)Example (before)

    class S {  
    public:  
           S() = default;  
    private:  
        S(const S&) = default;  
    };  
    
    void f(S);  // pass S by value  
    
    int main()  
    {  
        S s;  
        f(s);  // error C2248, can't invoke private copy constructor  
    }  
    

    예제(이후)Example (after)

    class S {  
    public:  
           S() = default;  
    private:  
        S(const S&) = default;  
    };  
    
    void f(const S&);  // pass S by reference  
    
    int main()  
    {  
        S s;  
        f(s);  
    }  
    
  • 특성 사용 ATL 코드 지원 중단(기본적으로 수준 1(/W1) 설정)Deprecation of attributed ATL code support (Level 1 (/W1) on-by-default)

    이전 버전의 컴파일러에서는 특성 사용 ATL 코드를 지원했습니다.Previous versions of the compiler supported attributed ATL code. Visual C++ 2008부터 시작된 특성 사용 ATL 코드 지원 제거의 다음 단계로 특성 사용 ATL 코드가 더 이상 사용되지 않습니다.As the next phase of removing support for attributed ATL code that began in Visual C++ 2008, attributed ATL code has been deprecated. 이제 컴파일러에서 사용되지 않는 이러한 종류의 코드를 식별하기 위해 컴파일러 경고 C4467을 실행합니다.The compiler now issues compiler warning C4467 to help identify this kind of deprecated code.

    warning C4467: Usage of ATL attributes is deprecated  
    

    컴파일러에서 지원이 제거될 때까지 특성 사용 ATL 코드를 계속 사용하려는 경우 /Wv:18 또는 /wd4467 명령줄 인수를 컴파일러에 전달하거나 소스 코드에 #pragma warning(disable:4467)을 추가하여 이 경고를 해제할 수 있습니다.If you want to continue using attributed ATL code until support is removed from the compiler, you can disable this warning by passing the /Wv:18 or /wd4467 command line arguments to the compiler, or by adding #pragma warning(disable:4467) in your source code.

    예제 1(이전)Example 1 (before)

              [uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]  
    class A {};  
    

    예제 1(이후)Example 1 (after)

    __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) A {};  
    

    사용되지 않는 ATL 특성의 사용을 방지하기 위해 아래 예제 코드와 같이 IDL 파일을 만들 수 있습니다.Sometimes you might need or want to create an IDL file to avoid the use deprecated ATL attributes, as in the example code below

    예제 2(이전)Example 2 (before)

    [emitidl];  
    [module(name="Foo")];  
    
    [object, local, uuid("9e66a290-4365-11d2-a997-00c04fa37ddb")]  
    __interface ICustom {  
        HRESULT Custom([in] long l, [out, retval] long *pLong);  
        [local] HRESULT CustomLocal([in] long l, [out, retval] long *pLong);  
    };  
    
    [coclass, appobject, uuid("9e66a294-4365-11d2-a997-00c04fa37ddb")]  
    class CFoo : public ICustom  
    {  
        // ...  
    };  
    

    먼저 *.idl 파일을 만듭니다. 생성된 vc140.idl 파일을 사용하여 인터페이스와 주석이 포함된 *.idl 파일을 가져올 수 있습니다.First, create the *.idl file; the vc140.idl generated file can be used to obtain an *.idl file containing the interfaces and annotations.

    그런 다음 빌드에 MIDL 단계를 추가하여 C++ 인터페이스 정의가 생성되었는지 확인합니다.Next, add a MIDL step to your build to make sure that the C++ interface definitions are generated.

    예제 2 IDL(이후)Example 2 IDL (after)

    import "docobj.idl";  
    
    [  
        object,local,uuid(9e66a290-4365-11d2-a997-00c04fa37ddb)  
    ]  
    
    interface ICustom : IUnknown {  
        HRESULT  Custom([in] long l, [out,retval] long *pLong);  
        [local] HRESULT  CustomLocal([in] long l, [out,retval] long *pLong);  
    };  
    
    [ version(1.0), uuid(29079a2c-5f3f-3325-99a1-3ec9c40988bb) ]  
    library Foo  
    {  
        importlib("stdole2.tlb");  
        importlib("olepro32.dll");  
            [  
                version(1.0),  
                appobject,uuid(9e66a294-4365-11d2-a997-00c04fa37ddb)  
            ]  
    
        coclass CFoo {  
            interface ICustom;  
        };  
    }  
    

    아래 예제 코드와 같이 구현 파일에서 직접 ATL을 사용합니다.Then, use ATL directly in the implementation file, as in the example code below.

    예제 2 구현(이후)Example 2 Implementation (after)

    #include <idl.header.h>  
    #include <atlbase.h>  
    
    class ATL_NO_VTABLE CFooImpl :  
        public ICustom,  
        public ATL::CComObjectRootEx<CComMultiThreadModel>  
    {  
    public:  
        BEGIN_COM_MAP(CFooImpl)  
        COM_INTERFACE_ENTRY(ICustom)  
        END_COM_MAP()  
    };  
    
  • 미리 컴파일된 헤더(PCH) 파일 및 일치하지 않는 #include 지시문(/Wall /WX에만 적용)Precompiled header (PCH) files and mismatched #include directives (only affects /Wall /WX)

    이전 버전의 컴파일러에서는 미리 컴파일된 헤더(PCH) 파일을 사용할 때 -Yc-Yu 컴파일 간에 일치하지 않는 소스 파일의 #include 지시문을 허용했습니다.Previous versions of the compiler accepted mismatched #include directives in source files between -Yc and -Yu compilations when using precompiled header (PCH) files. 이런 방식으로 작성된 코드는 컴파일러에서 더 이상 허용되지 않습니다.Code written in this way is no longer accepted by the compiler. PCH 파일 사용 시 일치하지 않는 #include 지시문을 식별하기 위해 이제 컴파일러에서 컴파일러 경고 CC4598을 실행합니다.The compiler now issues compiler warning CC4598 to help identify mismatched #include directives when using PCH files.

    warning C4598: 'b.h': included header file specified for Ycc.h at position 2 does not match Yuc.h at that position  
    

    예제(이전):Example (before):

    X.cpp(-Ycc.h)X.cpp (-Ycc.h)

    #include "a.h"  
    #include "b.h"  
    #include "c.h"  
    

    Z.cpp(-Yuc.h)Z.cpp (-Yuc.h)

    #include "b.h"  
    #include "a.h"  // mismatched order relative to X.cpp  
    #include "c.h"  
    

    예제(이후)Example (after)

    X.cpp(-Ycc.h)X.cpp (-Ycc.h)

    #include "a.h"  
    #include "b.h"   
    #include "c.h"  
    

    Z.cpp(-Yuc.h)Z.cpp (-Yuc.h)

    #include "a.h"  
    #include "b.h" // matched order relative to X.cpp  
    #include "c.h"  
    
  • 미리 컴파일된 헤더(PCH) 파일 및 일치하지 않는 include 지시문(/Wall /WX에만 적용)Precompiled header (PCH) files and mismatched include directories (only affects /Wall /WX)

    이전 버전의 컴파일러에서는 미리 컴파일된 헤더(PCH) 파일을 사용할 때 -Yc-Yu 컴파일 간에 일치하지 않는 컴파일러의 include 디렉터리(-I) 명령줄 인수를 허용했습니다.Previous versions of the compiler accepted mismatched include directory (-I) command line arguments to the compiler between -Yc and -Yu compilations when using precompiled header (PCH) files. 이런 방식으로 작성된 코드는 컴파일러에서 더 이상 허용되지 않습니다.Code written in this way is no longer accepted by the compiler. PCH 파일 사용 시 일치하지 않는 include 디렉터리(-I) 명령줄 인수를 식별하기 위해 이제 컴파일러에서 컴파일러 경고 CC4599를 실행합니다.The compiler now issues compiler warning CC4599 to help identify mismatched include directory (-I) command line arguments when using PCH files.

    warning C4599: '-I..' : specified for Ycc.h at position 1 does not match Yuc.h at that position  
    

    예제(이전)Example (before)

    cl /c /Wall /Ycc.h -I.. X.cpp  
    cl /c /Wall /Yuc.h Z.cpp  
    

    예제(이후)Example (after)

    cl /c /Wall /Ycc.h -I.. X.cpp  
    cl /c /Wall /Yuc.h -I.. Z.cpp