Visual Studio의 C++ 규칙 향상C++ conformance improvements in Visual Studio

Microsoft C++는 모든 릴리스에서 규칙 및 버그 수정을 향상합니다.Microsoft C++ makes conformance improvements and bug fixes in every release. 이 문서에는 주 릴리스와 버전별 개선 사항이 나와 있습니다.This article lists the improvements by major release, then by version. 버전별로 주요 버그 수정도 나와 있습니다.It also lists major bug fixes by version. 특정 버전의 변경 내용으로 바로 이동하려면 이 문서의 내용 목록을 사용합니다.To jump directly to the changes for a specific version, use the In this article list.

Visual Studio 2019 RTW(버전 16.0)의 규칙 향상Conformance improvements in Visual Studio 2019 RTW (version 16.0)

Visual Studio 2019 RTW에는 다음과 같은 Microsoft C++ 컴파일러(MSVC)의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.Visual Studio 2019 RTW contains the following conformance improvements, bug fixes, and behavior changes in the Microsoft C++ compiler (MSVC)

참고: C++20 기능은 컴파일러와 IntelliSense 모두에 대해 C++20 구현이 완료될 때까지 /std:c++latest 모드에서 사용할 수 있습니다.Note: C++20 features will be made available in /std:c++latest mode until the C++20 implementation is complete for both the compiler and IntelliSense. 이때 /std:c++20 컴파일러 모드가 도입됩니다.At that time, the /std:c++20 compiler mode will be introduced.

템플릿 및 오류 검색에 대한 향상된 모듈 지원Improved modules support for templates and error detection

모듈은 이제 공식적으로 C++20 표준에 속합니다.Modules are now officially in the C++20 standard. Visual Studio 2017 버전 15.9에는 향상된 지원이 추가되었습니다.Improved support was added in Visual Studio 2017 version 15.9. 자세한 내용은 MSVC 2017 버전 15.9를 사용하여 C++ 모듈의 템플릿 지원 및 오류 검색 향상을 참조하세요.For more information, see Better template support and error detection in C++ Modules with MSVC 2017 version 15.9.

집계 유형의 수정된 사양Modified specification of aggregate type

집계 유형의 사양이 C++20에서 변경되었습니다(사용자가 선언한 생성자로 집계 금지 참조).The specification of an aggregate type has changed in C++20 (see Prohibit aggregates with user-declared constructors). Visual Studio 2019의 /std:c++latest에서 사용자가 선언한 생성자가 있는 클래스(예: = default 또는 = delete로 선언된 생성자 포함)는 집계가 아닙니다.In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. 이전에는 사용자가 제공한 생성자만 클래스가 집계되지 못하도록 합니다.Previously, only user-provided constructors would disqualify a class from being an aggregate. 이 변경으로 인해 이러한 형식을 초기화할 수 있는 방법이 제한됩니다.This change puts additional restrictions on how such types can be initialized.

다음 코드는 Visual Studio 2017에서 오류 없이 컴파일되지만 /std:c++latest 아래의 Visual Studio 2019에서는 C2280 및 C2440 오류를 발생시킵니다.The following code compiles without errors in Visual Studio 2017 but raises errors C2280 and C2440 in Visual Studio 2019 under /std:c++latest:

struct A
{
    A() = delete; // user-declared ctor
};

struct B
{
    B() = default; // user-declared ctor
    int i = 0;
};

A a{}; // ill-formed in C++20, previously well-formed
B b = { 1 }; // ill-formed in C++20, previously well-formed

operator <=>에 대한 부분 지원Partial support for operator <=>

P0515R3 C++20에서는 "우주선 연산자"라고도 하는 <=> 3방향 비교 연산자를 소개합니다.P0515R3 C++20 introduces the <=> three-way comparison operator, also known as the "spaceship operator". /std:c++latest 모드의 Visual Studio 2019는 현재 허용되지 않는 구문 오류를 발생시켜 연산자에 대한 부분 지원을 도입합니다.Visual Studio 2019 in /std:c++latest mode introduces partial support for the operator by raising errors for syntax that is now disallowed. 예를 들어 다음 코드는 Visual Studio 2017에서 오류 없이 컴파일되지만 /std:c++latest 아래의 Visual Studio 2019에서는 여러 오류가 발생합니다.For example, the following code compiles without errors in Visual Studio 2017 but raises multiple errors in Visual Studio 2019 under /std:c++latest:

struct S
{
    bool operator<=(const S&) const { return true; }
};

template <bool (S::*)(const S&) const>
struct U { };

int main(int argc, char** argv)
{
    U<&S::operator<=> u; // In Visual Studio 2019 raises C2039, 2065, 2146.
}

오류를 방지하려면, 위반하는 줄에서 최종 꺾쇠괄호 앞에 공백을 삽입합니다. U<&S::operator<= > u;To avoid the errors, insert a space in the offending line before the final angle bracket: U<&S::operator<= > u;.

일치하지 않는 cv 한정자가 있는 유형에 대한 참조References to types with mismatched cv-qualifiers

이전에는 MSVC에서 최상위 수준 아래에 일치하지 않는 cv 한정자가 있는 형식의 참조를 직접 바인딩할 수 있었습니다.Previously, MSVC allowed direct binding of a reference from a type with mismatched cv-qualifiers below the top level. 이 바인딩은 참조가 나타내는 것으로 추정되는 const 데이터의 수정을 허용할 수 있었습니다.This binding could allow modification of supposedly const data referred to by the reference. 이제 컴파일러에서 표준에 따라 임시 바인딩을 만듭니다.The compiler now creates a temporary, as required by the standard. Visual Studio 2017에서 다음 코드는 경고 없이 컴파일됩니다.In Visual Studio 2017, the following code compiles without warnings. Visual Studio 2019에서 컴파일러는 경고 C4172: <func:#1 "?PData@X@@QBEABQBXXZ"> 로컬 변수 또는 임시 주소를 반환합니다.In Visual Studio 2019, the compiler raises warning C4172: <func:#1 "?PData@X@@QBEABQBXXZ"> returning address of local variable or temporary.

struct X
{
    const void* const& PData() const
    {
        return _pv;
    }

    void* _pv;
};

int main()
{
    X x;
    auto p = x.PData(); // C4172
}

reinterpret_cast 오버로드된 함수에서reinterpret_cast from an overloaded function

reinterpret_cast의 인수는 오버로드된 함수의 주소가 허용되는 컨텍스트 중 하나가 아닙니다.The argument to reinterpret_cast isn't one of the contexts in which the address of an overloaded function is permitted. 다음 코드는 Visual Studio 2017에서 오류 없이 컴파일되지만 Visual Studio 2019에서는 C2440: '오버로드된 함수'에서 'fp'로 변환될 수 없음을 발생시킵니다.The following code compiles without errors in Visual Studio 2017, but in Visual Studio 2019 it raises C2440: cannot convert from 'overloaded-function' to 'fp':

int f(int) { return 1; }
int f(float) { return .1f; }
using fp = int(*)(int);

int main()
{
    fp r = reinterpret_cast<fp>(&f);
}

오류를 방지하려면 이 시나리오에 허용된 캐스트를 사용합니다.To avoid the error, use an allowed cast for this scenario:

int f(int);
int f(float);
using fp = int(*)(int);

int main()
{
    fp r = static_cast<fp>(&f); // or just &f;
}

람다 클로저Lambda closures

C++14에서 람다 클로저 형식은 리터럴이 아닙니다.In C++14, lambda closure types aren't literals. 이 규칙의 기본 결과는 람다가 constexpr 변수에 할당되지 않을 수 있다는 것입니다.The primary consequence of this rule is that a lambda may not be assigned to a constexpr variable. 다음 코드는 Visual Studio 2017에서 오류 없이 컴파일되지만, Visual Studio 2019에서는 ‘C2127: ‘l’: 비상수 식으로 ‘constexpr’ 엔터티 초기화가 잘못되었습니다.’가 발생합니다. The following code compiles without errors in Visual Studio 2017, but in Visual Studio 2019 it raises C2127: 'l': illegal initialization of 'constexpr' entity with a non-constant expression:

int main()
{
    constexpr auto l = [] {}; // C2127 in VS2019
}

오류를 방지하려면 constexpr 한정자를 제거하거나 규칙 모드를 /std:c++17로 변경합니다.To avoid the error, either remove the constexpr qualifier, or else change the conformance mode to /std:c++17.

std::create_directory 실패 코드std::create_directory failure codes

C++20에서 P1164를 무조건으로 구현했습니다.Implemented P1164 from C++20 unconditionally. 이렇게 하면 대상이 이미 실패한 디렉터리인지 여부를 확인하기 위해 std::create_directory가 변경됩니다.This changes std::create_directory to check whether the target was already a directory on failure. 이전에는 모든 ERROR_ALREADY_EXISTS 형식 오류가 success-but-directory-not-created 코드로 변경되었습니다.Previously, all ERROR_ALREADY_EXISTS type errors were turned into success-but-directory-not-created codes.

operator<<(std::ostream, nullptr_t)

LWG 2221당 스크림에 nullptrs를 쓰기 위해 operator<<(std::ostream, nullptr_t)을 추가했습니다.Per LWG 2221, added operator<<(std::ostream, nullptr_t) for writing nullptrs to streams.

추가 병렬 알고리즘Additional parallel algorithms

is_sorted, is_sorted_until, is_partitioned, set_difference, set_intersection, is_heapis_heap_until의 새 병렬 버전.New parallel versions of is_sorted, is_sorted_until, is_partitioned, set_difference, set_intersection, is_heap, and is_heap_until.

원자성 초기화atomic initialization

P0883 "원자성 초기화 수정"std::atomic을 변경하여 포함된 T를 기본 초기화하는 대신 값을 초기화합니다.P0883 "Fixing atomic initialization" changes std::atomic to value-initialize the contained T rather than default-initializing it. 이 수정 내용은 Microsoft 표준 라이브러리에서 Clang/LLVM을 사용할 때 활성화됩니다.The fix is enabled when using Clang/LLVM with the Microsoft standard library. 현재 Microsoft C++ 컴파일러에서 constexpr 처리 중인 버그에 대한 해결 방법으로 사용할 수 없습니다.It's currently disabled for the Microsoft C++ compiler, as a workaround for a bug in constexpr processing.

remove_cvrefremove_cvref_tremove_cvref and remove_cvref_t

P0550에서 remove_cvrefremove_cvref_t 형식 특성을 구현했습니다.Implemented the remove_cvref and remove_cvref_t type traits from P0550. 이러한 특성은 함수 및 배열이 손상되지 않는 유형에서 포인터(std::decaystd::decay_t와는 달리)로 참조 및 cv 한정자를 제거합니다.These remove reference-ness and cv-qualification from a type without decaying functions and arrays to pointers (unlike std::decay and std::decay_t).

기능 테스트 매크로Feature-test macros

P0941R2 - feature-test 매크로__has_cpp_attribute에 대한 지원으로 완료되었습니다.P0941R2 - feature-test macros is complete, with support for __has_cpp_attribute. 기능 테스트 매크로는 모든 표준 모드에서 지원됩니다.Feature-test macros are supported in all standard modes.

사용자 선언 생성자를 사용하여 집계 금지Prohibit aggregates with user-declared constructors

C++20 P1008R1 - 사용자 선언 생성자를 사용하여 집계 금지가 완료되었습니다.C++20 P1008R1 - prohibiting aggregates with user-declared constructors is complete.

16.1의 규칙 향상Conformance improvements in 16.1

char8_tchar8_t

P0482r6.P0482r6. C++20은 UTF-8 코드 단위를 나타내는 데 사용되는 새로운 문자 형식을 추가합니다.C++20 adds a new character type that is used to represent UTF-8 code units. C++20의 u8 문자열 리터럴에는 이전의 const char[N] 대신 const char8_t[N] 형식이 있습니다.u8 string literals in C++20 have type const char8_t[N] instead of const char[N], which was the case previously. N2231에서 C 표준에 대해 유사한 변경이 제안되었습니다.Similar changes have been proposed for the C standard in N2231. char8_t 이전 버전과의 호환성 수정에 대한 제안은 P1423r0에서 제공됩니다.Suggestions for char8_t backward compatibility remediation are given in P1423r0. Microsoft C++ 컴파일러는 /Zc:char8_t 컴파일러 옵션을 지정할 때 Visual Studio 2019 버전 16.1에서 char8_t 지원을 추가합니다.The Microsoft C++ compiler adds support for char8_t in Visual Studio 2019 version 16.1 when you specify the /Zc:char8_t compiler option. 향후 /Zc:char8_t- 를 통해 C++17 동작으로 되돌릴 수 있는 /std:c++latest로 지원될 예정입니다.In the future, it will be supported with /std:c++latest, which can be reverted to C++17 behavior via /Zc:char8_t-. IntelliSense를 지원하는 EDG 컴파일러는 이 기능을 아직 지원하지 않으므로 실제 컴파일에 영향을 주지 않는 IntelliSense 전용 의사 오류가 표시됩니다.The EDG compiler that powers IntelliSense doesn't yet support it, so you'll see spurious IntelliSense-only errors that don't impact the actual compilation.

Example

const char* s = u8"Hello"; // C++17
const char8_t* s = u8"Hello"; // C++20

std::type_identity 메타 함수 및 std:: identity 함수 개체std::type_identity metafunction and std::identity function object

P0887R1 type_identity.P0887R1 type_identity. 사용되지 않는 std::identity 클래스 템플릿 확장이 제거되었으며 C++20 std::type_identity 메타 함수 및 std::identity 함수 개체로 대체되었습니다.The deprecated std::identity class template extension has been removed, and replaced with the C++20 std::type_identity metafunction and std::identity function object. 둘 다 /std:c++latest에서만 사용할 수 있습니다.Both are available only under /std:c++latest.

다음 예제에서는 Visual Studio 2017에서 std::identity(<type_traits>에서 정의됨)에 대한 사용 중단 경고 C4996을 생성합니다.The following example produces deprecation warning C4996 for std::identity (defined in <type_traits>) in Visual Studio 2017:

#include <type_traits>

using T = std::identity<int>::type;
T x, y = std::identity<T>{}(x);
int i = 42;
long j = std::identity<long>{}(i);

다음 예제에서는 새 std::identity(<functional>에서 정의됨)를 std::type_identity와 함께 사용하는 방법을 보여줍니다.The following example shows how to use the new std::identity (defined in <functional>) together with the new std::type_identity:

#include <type_traits>
#include <functional>

using T = std::type_identity<int>::type;
T x, y = std::identity{}(x);
int i = 42;
long j = static_cast<long>(i);

일반 람다에 대한 구문 검사Syntax checks for generic lambdas

새 람다 프로세서는 /std:c++latest 또는 /experimental:newLambdaProcessor를 사용하는 다른 언어 모드 아래의 일반 람다에서 몇 가지 규칙 모드 구문 검사를 활성화합니다.The new lambda processor enables some conformance-mode syntactic checks in generic lambdas, under /std:c++latest or under any other language mode with /experimental:newLambdaProcessor.

Visual Studio 2017에서 이 코드는 경고 없이 컴파일되지만 Visual Studio 2019에서는 C2760 구문 오류: 예기치 않은 토큰 '<id-expr>', expected 'id-expression' 오류가 생성됩니다.In Visual Studio 2017, this code compiles without warnings, but in Visual Studio 2019 it produces error C2760 syntax error: unexpected token '<id-expr>', expected 'id-expression':

void f() {
    auto a = [](auto arg) {
        decltype(arg)::Type t;
    };
}

다음 예제는 올바른 구문을 보여주고, 이제 컴파일러에 의해 적용됩니다.The following example shows the correct syntax, now enforced by the compiler:

void f() {
    auto a = [](auto arg) {
        typename decltype(arg)::Type t;
    };
}

함수 호출에 대한 인수 종속 조회Argument-dependent lookup for function calls

P0846R0(C++20) 명시적 템플릿 인수를 사용하는 함수 호출 식에 대한 인수 종속 조회를 통해 함수 템플릿을 찾는 기능이 향상되었습니다.P0846R0 (C++20) Increased ability to find function templates via argument-dependent lookup for function call expressions with explicit template arguments. /std:c++latest가 필요합니다.Requires /std:c++latest.

지정된 초기화Designated initialization

P0329R4(C++20) 지정된 초기화를 통해 Type t { .member = expr } 구문을 사용하여 지정된 멤버를 집계 초기화에서 선택할 수 있습니다.P0329R4 (C++20) Designated initialization allows specific members to be selected in aggregate initialization by using the Type t { .member = expr } syntax. /std:c++latest가 필요합니다.Requires /std:c++latest.

신규 및 업데이트된 표준 라이브러리 함수(C++20)New and updated standard library functions (C++20)

  • basic_stringbasic_string_view에 대한 starts_with()ends_with().starts_with() and ends_with() for basic_string and basic_string_view.
  • 연관 컨테이너에 대한 contains().contains() for associative containers.
  • listforward_list에 대한 remove(), remove_if()unique()가 이제 size_type을 반환합니다.remove(), remove_if(), and unique() for list and forward_list now return size_type.
  • shift_left()shift_right()가 <algorithm>에 추가되었습니다.shift_left() and shift_right() added to <algorithm>.

16.2의 규칙 향상Conformance improvements in 16.2

noexcept constexpr 함수noexcept constexpr functions

constexpr 함수는 상수 식에서 사용될 때 더 이상 기본적으로 noexcept로 고려되지 않습니다.Constexpr functions are no longer considered noexcept by default when used in a constant expression. 이 동작 변경은 CWG 1351 문제의 해결로 인한 것이며, /permissive-에서 사용 설정됩니다.This behavior change comes from the resolution of CWG 1351 and is enabled in /permissive-. 다음 예제는 Visual Studio 2019 버전 16.1 이전 버전에서 컴파일되지만 Visual Studio 2019 버전 16.2에서 C2338을 생성합니다.The following example compiles in Visual Studio 2019 version 16.1 and earlier, but produces C2338 in Visual Studio 2019 version 16.2:

constexpr int f() { return 0; }

int main() {
    static_assert(noexcept(f()), "f should be noexcept"); // C2338 in 16.2
}

오류를 해결하려면 함수 선언에 noexcept 식을 추가합니다.To fix the error, add the noexcept expression to the function declaration:

constexpr int f() noexcept { return 0; }

int main() {
    static_assert(noexcept(f()), "f should be noexcept");
}

열거형 형식이 다른 이진 식Binary expressions with different enum types

하나는 열거형 형식이고 다른 하나는 다른 열거형 형식이거나 부동 소수점 형식인 피연산자에 일반적인 산술 변환을 적용하는 기능은 C++20에서 더 이상 사용되지 않습니다(P1120R0).The ability to apply the usual arithmetic conversions on operands where one is of enumeration type and the other is of a different enumeration type or a floating-point type is deprecated in C++20 (P1120R0). Visual Studio 2019 버전 16.2 이상에서 /std:c++latest 컴파일러 옵션을 사용하는 경우 다음 코드는 수준 4 경고를 생성합니다.In Visual Studio 2019 version 16.2 and later, the following code produces a level 4 warning when the /std:c++latest compiler option is enabled:

enum E1 { a };
enum E2 { b };
int main() {
    int i = a | b; // warning C5054: operator '|': deprecated between enumerations of different types
}

이 경고를 방지하려면 static_cast를 사용하여 두 번째 피연산자를 변환합니다.To avoid the warning, use static_cast to convert the second operand:

enum E1 { a };
enum E2 { b };
int main() {
  int i = a | static_cast<int>(b);
}

열거형 및 부동 소수점 형식을 사용하는 이진 식Binary expressions with enumeration and floating point types

하나는 열거형 형식이고 다른 하나는 다른 열거형 형식이거나 부동 소수점 형식인 피연산자에 일반적인 산술 변환을 적용하는 기능은 C++20에서 더 이상 사용되지 않습니다(P1120R0).The ability to apply the usual arithmetic conversions on operands where one is of enumeration type and the other is of a different enumeration type or a floating-point type is deprecated in C++20 (P1120R0). 즉, 열거형과 부동 소수점 형식 간에 이진 연산을 사용하면 /std:c++latest 컴파일러 옵션이 사용 설정된 경우 경고가 발생합니다.In other words, using a binary operation between an enumeration and a floating-point type is now a warning when the /std:c++latest compiler option is enabled:

enum E1 { a };
int main() {
  double i = a * 1.1;
}

이 경고를 방지하려면 static_cast를 사용하여 두 번째 피연산자를 변환합니다.To avoid the warning, use static_cast to convert the second operand:

enum E1 { a };
int main() {
   double i = static_cast<int>(a) * 1.1;
}

배열의 같음 및 관계 비교Equality and relational comparisons of arrays

배열 형식의 두 피연산자 간 같음 및 관계 비교는 C++20에서 사용되지 않습니다(P1120R0).Equality and relational comparisons between two operands of array type are deprecated in C++20 (P1120R0). 즉, 두 배열 간의 비교 연산(순위 및 범위 유사성과 관계없이)을 사용하면 경고가 발생합니다.In other words, a comparison operation between two arrays (regardless of rank and extent similarities) is a now a warning. Visual Studio 2019 버전 16.2부터 /std:c++latest 컴파일러 옵션이 사용 설정된 경우 다음 코드는 C5056: operator '==': deprecated for array types를 생성합니다.Starting in Visual Studio 2019 version 16.2, the following code produces C5056: operator '==': deprecated for array types when the /std:c++latest compiler option is enabled:

int main() {
    int a[] = { 1, 2, 3 };
    int b[] = { 1, 2, 3 };
    if (a == b) { return 1; }
}

이 경고를 방지하기 위해 첫 번째 요소의 주소를 비교할 수 있습니다.To avoid the warning, you can compare the addresses of the first elements:

int main() {
    int a[] = { 1, 2, 3 };
    int b[] = { 1, 2, 3 };
    if (&a[0] == &b[0]) { return 1; }
}

두 배열의 콘텐츠가 동일한지 여부를 확인하려면 std::equal 함수를 사용합니다.To determine whether the contents of two arrays are equal, use the std::equal function:

std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b));

우주선 연산자 정의가 == 및 !=에 미치는 영향Effect of defining spaceship operator on == and !=

우주선 연산자가 = default로 표시되지 않는 한 우주선 연산자 정의( <=> )만으로는 더 이상 == 또는 != 을 포함하는 식을 다시 생성하지 않습니다(P1185R2).A definition of the spaceship operator (<=>) alone will no longer rewrite expressions involving == or != unless the spaceship operator is marked as = default (P1185R2). 다음 예제는 Visual Studio 2019 RTW 및 버전 16.1에서 컴파일되지만 Visual Studio 2019 버전 16.2에서 C2678을 생성합니다.The following example compiles in Visual Studio 2019 RTW and version 16.1, but produces C2678 in Visual Studio 2019 version 16.2:

#include <compare>

struct S {
  int a;
  auto operator<=>(const S& rhs) const {
    return a <=> rhs.a;
  }
};
bool eq(const S& lhs, const S& rhs) {
  return lhs == rhs;
}
bool neq(const S& lhs, const S& rhs) {
    return lhs != rhs;
}

이 오류를 방지하려면 == 연산자를 정의하거나 기본값으로 선언합니다.To avoid the error, define the operator== or declare it as defaulted:

#include <compare>

struct S {
  int a;
  auto operator<=>(const S& rhs) const {
    return a <=> rhs.a;
  }
  bool operator==(const S&) const = default;
};
bool eq(const S& lhs, const S& rhs) {
  return lhs == rhs;
}
bool neq(const S& lhs, const S& rhs) {
    return lhs != rhs;
}

표준 라이브러리 향상Standard Library improvements

  • 고정/지수 전체 자릿수를 가진 <charconv> to_chars().<charconv> to_chars() with fixed/scientific precision. (버전 16.4에서는 일반 전체 자릿수를 사용할 계획입니다.)(General precision is currently planned for 16.4.)
  • P0020R6: atomic<float>, atomic<double>, atomic<long double>P0020R6: atomic<float>, atomic<double>, atomic<long double>
  • P0463R1: endianP0463R1: endian
  • P0482R6: char8_t에 대한 라이브러리 지원P0482R6: Library Support For char8_t
  • P0600R1: STL, 파트 1에 대한 [[nodiscard]]P0600R1: [[nodiscard]] For The STL, Part 1
  • P0653R2: to_address()P0653R2: to_address()
  • P0754R2: <version>P0754R2: <version>
  • P0771R1: std::function의 이동 생성자에 대한 noexceptP0771R1: noexcept For std::function's move constructor

Visual Studio 2019 버전 16.3의 규칙 향상Conformance improvements in Visual Studio 2019 version 16.3

Char*의 스트림 추출 연산자가 제거됨Stream extraction operators for char* removed

포인터와 문자 간에 대한 스트림 추출 연산자가 제거되고 문자 배열에 대한 추출 연산자로 바뀌었습니다(P0487R1에 따라).Stream extraction operators for pointer-to-characters have been removed and replaced by extraction operators for array-of-characters (per P0487R1). WG21은 제거된 오버로드를 안전하지 않은 것으로 간주합니다.WG21 considers the removed overloads to be unsafe. /std:c++latest 모드에서 다음 예제는 이제 C2679: binary '>>': 'char*' 형식의 오른쪽 피연산자를 사용하는 연산자를 찾을 수 없음(또는 허용되는 변환이 없음) 을 생성합니다.In /std:c++latest mode, the following example now produces C2679: binary '>>': no operator found which takes a right-hand operand of type 'char*' (or there is no acceptable conversion):

   char x[42];
   char* p = x;
   std::cin >> std::setw(42);
   std::cin >> p;

오류를 방지하려면 char[] 변수와 함께 추출 연산자를 사용합니다.To avoid the error, use the extraction operator with a char[] variable:

char x[42];
std::cin >> x;

새 키워드 requiresconceptNew keywords requires and concept

새 키워드 requiresconcept가 Microsoft C++ 컴파일러에 추가되었습니다.New keywords requires and concept have been added to the Microsoft C++ compiler. /std:c++latest 모드에서 두 키워드 중 하나를 식별자로 사용하려고 하면 컴파일러는 C2059: 구문 오류를 발생시킵니다.If you attempt to use either one as an identifier in /std:c++latest mode, the compiler will raise C2059: syntax error.

생성자를 형식 이름으로 사용할 수 없음Constructors as type names disallowed

생성자 이름이 클래스 템플릿 특수화에 대한 별칭 뒤의 정규화된 이름에 표시되는 경우에는 더 이상 삽입된 클래스 이름으로 간주하지 않습니다.Constructor names are no longer considered injected-class-names when they appear in a qualified name after an alias to a class template specialization. 이전에는 생성자를 형식 이름으로 사용하여 다른 엔터티를 선언할 수 있었습니다.This previously allowed the use of constructors as a type name to declare other entities. 다음 예제에서는 C3646: ‘TotalDuration’: 알 수 없는 재정의 지정자를 생성합니다.The following example now produces C3646: 'TotalDuration': unknown override specifier:

#include <chrono>

class Foo {
   std::chrono::milliseconds::duration TotalDuration{};
};

오류를 방지하려면 다음과 같이 TotalDuration을 선언합니다.To avoid the error, declare TotalDuration as shown here:

#include <chrono>

class Foo {
  std::chrono::milliseconds TotalDuration {};
};

Extern “C” 함수에 대해 더 엄격해진 검사Stricter checking of extern "C" functions

extern "C" 함수가 다른 네임스페이스에서 선언된 경우 이전 버전의 Microsoft C++ 컴파일러는 선언이 호환되는지 여부를 확인하지 않았습니다.If an extern "C" function was declared in different namespaces, previous versions of the Microsoft C++ compiler did not check whether the declarations were compatible. Visual Studio 2019 버전 16.3에서는 컴파일러가 이러한 검사를 수행합니다.In Visual Studio 2019 version 16.3, the compiler performs such a check. /permissive- 모드에서 다음 코드는 C2371 : 재정의; 다른 기본 형식C2733 C 링크로 함수를 오버로드할 수 없음을 생성합니다.In /permissive- mode, the following code produces C2371 : redefinition; different basic types and C2733 you cannot overload a function with C linkage:

using BOOL = int;

namespace N
{
   extern "C" void f(int, int, int, bool);
}

void g()
{
   N::f(0, 1, 2, false);
}

extern "C" void f(int, int, int, BOOL){}

앞의 예제에서 오류를 방지하려면 두 f 선언 모두에서 일관적으로 BOOL 대신 bool을 사용합니다.To avoid the errors in the previous example, use bool instead of BOOL consistently in both declarations of f.

표준 라이브러리 향상Standard Library improvements

비표준 헤더 <stdexcpt.h> 및 <typeinfo.h>가 제거되었습니다.The non-standard headers <stdexcpt.h> and <typeinfo.h> have been removed. 이러한 비표준 헤더를 포함하는 코드는 대신 표준 헤더 <exception> 및 <typeinfo>를 각각 포함해야 합니다.Code that includes them should instead include the standard headers <exception> and <typeinfo>, respectively.

Visual Studio 2019의 버그 수정 및 동작 변경Bug fixes and behavior changes in Visual Studio 2019

constexpr 함수의 reinterpret_castReinterpret_cast in a constexpr function

reinterpret_castconstexpr 함수에서 사용할 수 없습니다.A reinterpret_cast is illegal in a constexpr function. Microsoft C++ 컴파일러는 이전에 constexpr 컨텍스트에서 사용되는 경우에만 reinterpret_cast를 거부했습니다.The Microsoft C++ compiler would previously reject reinterpret_cast only if it were used in a constexpr context. Visual Studio 2019에서는 모든 언어 표준 모드에서 컴파일러가 constexpr 함수의 정의에서 reinterpret_cast를 정확히 진단합니다.In Visual Studio 2019, in all language standards modes, the compiler correctly diagnoses a reinterpret_cast in the definition of a constexpr function. 이제 다음 코드는 C3615: constexpr 함수 ‘f’는 상수 식이 될 수 없음을 생성합니다.The following code now produces C3615: constexpr function 'f' cannot result in a constant expression.

long long i = 0;
constexpr void f() {
    int* a = reinterpret_cast<int*>(i);
}

오류를 방지하려면 함수 선언에서 constexpr 한정자를 제거합니다.To avoid the error, remove the constexpr modifier from the function declaration.

Basic_string 범위 생성자에 대한 올바른 진단Correct diagnostics for basic_string range constructor

Visual Studio 2019에서 basic_string 범위 생성자는 더 이상 static_cast를 사용하여 컴파일러 진단을 표시하지 않습니다.In Visual Studio 2019, the basic_string range constructor no longer suppresses compiler diagnostics with static_cast. 다음 코드는 out을 초기화할 때 wchar_t에서 char로 데이터가 손실될 수 있음에도 불구하고 Visual Studio 2017에서 경고 없이 컴파일됩니다.The following code compiles without warnings in Visual Studio 2017, despite the possible loss of data from wchar_t to char when initializing out:

std::wstring ws = /* … */;
std::string out(ws.begin(), ws.end());

Visual Studio 2019에서 C4244: 'argument': 데이터 손실이 가능한 'wchar_t'에서 'const _Elem'으로 변환이 발생합니다.Visual Studio 2019 correctly raises C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data. 경고를 방지하려면 다음 예제와 같이 std::string을 초기화할 수 있습니다.To avoid the warning, you can initialize the std::string as shown in this example:

std::wstring ws = L"Hello world";
std::string out;
for (wchar_t ch : ws)
{
    out.push_back(static_cast<char>(ch));
}

/clr 또는 /ZW 아래에 += 및 -=에 대한 잘못된 호출 이제 올바르게 검색됩니다.Incorrect calls to += and -= under /clr or /ZW are now correctly detected

Visual Studio 2017에서는 컴파일러가 자동으로 오류를 무시하고 /clr 또는 /ZW 아래의 잘못된 += 및 -= 호출에 대한 코드를 생성하지 않는 버그가 도입되었습니다.A bug was introduced in Visual Studio 2017 that caused the compiler to silently ignore errors and generate no code for the invalid calls to += and -= under /clr or /ZW. 다음 코드는 Visual Studio 2017에서 오류 없이 컴파일되지만 Visual Studio 2019에서는 오류 C2845: 'System::string ^': 이 형식에서는 포인터 산술이 허용되지 않음을 올바르게 발생시킵니다.The following code compiles without errors in Visual Studio 2017 but in Visual Studio 2019 it correctly raises error C2845: 'System::String ^': pointer arithmetic not allowed on this type:

public enum class E { e };

void f(System::String ^s)
{
    s += E::e; // C2845 in VS2019
}

이 예제에서 오류를 방지하려면 ToString() 메서드(s += E::e.ToString();)와 함께 연산자를 사용합니다.To avoid the error in this example, use the operator with the ToString() method: s += E::e.ToString();.

인라인 정적 데이터 멤버에 대한 이니셜라이저Initializers for inline static data members

이제 인라인정적 constexpr 이니셜라이저 내에서 잘못된 멤버 액세스가 올바르게 검색됩니다.Invalid member accesses within inline and static constexpr initializers are now correctly detected. 다음 예제에서는 Visual Studio 2017에서 오류 없이 컴파일되지만 /std:c++17 모드 아래에 Visual Studio 2019에서는 오류 C2248: 'X' 클래스에 선언된 프라이빗 멤버에 액세스할 수 없음을 발생시킵니다.The following example compiles without error in Visual Studio 2017, but in Visual Studio 2019 under /std:c++17 mode it raises error C2248: cannot access private member declared in class 'X'.

struct X
{
    private:
        static inline const int c = 1000;
};

struct Y : X
{
    static inline int d = c; // C2248 in Visual Studio 2019
};

오류를 방지하려면 X::c 멤버를 보호됨으로 선언합니다.To avoid the error, declare the member X::c as protected:

struct X
{
    protected:
        static inline const int c = 1000;
};

C4800 복원C4800 reinstated

MSVC에서는 bool로의 암시적 변환에 대해 성능 경고 C4800을 사용했습니다.MSVC used to have a performance warning C4800 about implicit conversion to bool. 이 경고는 너무 번거롭고 표시되지 않도록 설정할 수 없어 Visual Studio 2017에서 제거되었습니다.It was too noisy and could not be suppressed, leading us to remove it in Visual Studio 2017. 그러나 Visual Studio 2017의 수명 주기 동안 이 경고를 통해 해결되었던 유용한 사례에 대한 많은 피드백을 받았습니다.However, over the lifecycle of Visual Studio 2017 we got lots of feedback on the useful cases it was solving. Visual Studio 2019에서는 설명을 포함하는 C4165와 함께 신중하게 조정된 C4800이 다시 추가되었습니다.We bring back in Visual Studio 2019 a carefully tailored C4800, along with the explanatory C4165. 두 경고는 명시적 캐스트 또는 적절한 형식의 0 비교를 사용하여 표시되지 않도록 쉽게 설정할 수 있습니다.Both of these warnings can be easily suppressed with either an explicit cast, or comparison to 0 of the appropriate type. C4800은 off-by-default 수준 4 경고이고 C4165는 off-by-default 수준 3 경고입니다.C4800 is an off-by-default level 4 warning, and C4165 is an off-by-default level 3 warning. 둘 다 /Wall 컴파일러 옵션을 사용하여 검색할 수 있습니다.Both are discoverable by using the /Wall compiler option.

다음 예제에서는 /Wall에서 C4800 및 C4165를 발생시킵니다.The following example raises C4800 and C4165 under /Wall:

bool test(IUnknown* p)
{
    bool valid = p; // warning C4800: Implicit conversion from 'IUnknown*' to bool. Possible information loss
    IDispatch* d = nullptr;
    HRESULT hr = p->QueryInterface(__uuidof(IDispatch), reinterpret_cast<void**>(&d));
    return hr; // warning C4165: 'HRESULT' is being converted to 'bool'; are you sure this is what you want?
}

이전 예제에서 경고를 방지하려면 다음과 같은 코드를 작성하면 됩니다.To avoid the warnings in the previous example, you can write the code like this:

bool test(IUnknown* p)
{
    bool valid = p != nullptr; // OK
    IDispatch* d = nullptr;
    HRESULT hr = p->QueryInterface(__uuidof(IDispatch), reinterpret_cast<void**>(&d));
    return SUCCEEDED(hr);  // OK
}

로컬 클래스 멤버 함수에 본문이 없습니다.Local class member function doesn't have a body

Visual Studio 2017에서 C4822: 로컬 클래스 멤버 함수에 본문이 없음은 컴파일러 옵션 /w14822가 명시적으로 설정된 경우에만 발생합니다. /Wall에는 표시되지 않습니다.In Visual Studio 2017, C4822: Local class member function doesn't have a body is raised only when compiler option /w14822 is explicitly set; it isn't shown with /Wall. Visual Studio 2019에서 C4822는 /w14822를 명시적으로 설정하지 않고도 /Wall에서 검색할 수 있도록 하는 off-by-default 경고입니다.In Visual Studio 2019, C4822 is an off-by-default warning, which makes it discoverable under /Wall without having to set /w14822 explicitly.

void example()
{
    struct A
        {
            int boo(); // warning C4822
        };
}

constexpr if 문을 포함하는 함수 템플릿 본문Function template bodies containing constexpr if statements

if constexpr 문을 포함하는 템플릿 함수 본문에 일부 /permissive- 구문 분석 관련 검사가 활성화되어 있습니다.Template function bodies containing if constexpr statements have some /permissive- parsing-related checks enabled. 예를 들어 Visual Studio 2017에서 다음 코드는 C7510: ‘Type’: 종속 형식 이름을 사용하는 경우 ‘typename’으로 시작해야 합니다. 를 생성합니다. 단, /permissive- 옵션이 설정되지 않은 경우에만 해당합니다.For example, in Visual Studio 2017 the following code produces C7510: 'Type': use of dependent type name must be prefixed with 'typename' only if the /permissive- option isn't set. Visual Studio 2019에서는 /permissive- 옵션이 설정된 경우에도 동일한 코드에서 오류가 발생합니다.In Visual Studio 2019 the same code raises errors even when the /permissive- option is set:

template <typename T>

int f()
{
    T::Type a; // error C7510

    if constexpr (T::val)
    {
        return 1;
    }
    else
    {
        return 2;
    }
}

struct X
{
    using Type = X;
    constexpr static int val = 1;
};

int main()
{
    return f<X>();
}

이 오류를 방지하려면 a 선언 typename 키워드를 추가합니다.typename T::Type a;To avoid the error, add thetypename keyword to the declaration of a: typename T::Type a;.

인라인 어셈블리 코드는 람다 식에서 지원되지 않음Inline assembly code isn't supported in a lambda expression

Microsoft C++ 팀은 최근 람다 내에서 인라인 어셈블러를 사용하면 런타임 시 ebp(반환 주소 레지스터)가 손상될 수 있는 보안 문제를 인식하게 되었습니다.The Microsoft C++ team was recently made aware of a security issue in which the use of inline-assembler within a lambda could lead to the corruption of ebp (the return address register) at runtime. 악의적인 공격자가 이 시나리오를 활용할 수 있었습니다.A malicious attacker could possibly take advantage of this scenario. 이 문제의 특성, 인라인 어셈블러가 x86에서만 지원된다는 팩트, 인라인 어셈블러와 다른 컴파일러 부분 간의 상호 작용 부족 등을 고려할 때, 이 문제의 가장 안전한 솔루션은 람다 식 내에서 인라인 어셈블러를 허용하지 않는 것이었습니다.Given the nature of the issue, the fact that inline assembler is only supported on x86, and the poor interaction between the inline assembler and the rest of the compiler, the safest solution to this problem was to disallow inline assembler within a lambda expression.

발견된 ‘실제’ 사례에서 인라인 어셈블러가 람다 식 내에서 사용되는 유일한 목적은 반환 주소를 캡처하기 위한 것이었습니다.The only use of inline assembler within a lambda expression that we have found 'in the wild' was to capture the return address. 이 시나리오에서는 컴파일러 고유의 _ReturnAddress()를 사용하여 모든 플랫폼에서 반환 주소를 캡처할 수 있습니다.In this scenario, you can capture the return address on all platforms simply by using a compiler intrinsic _ReturnAddress().

다음 코드는 Visual Studio 2017 15.9 및 Visual Studio 2019에서 C7552: 인라인 어셈블러는 람다에서 지원되지 않음을 생성합니다.The following code produces C7552: inline assembler is not supported in a lambda in both Visual Studio 2017 15.9 and in Visual Studio 2019:

#include <cstdio>

int f()
{
    int y = 1724;
    int x = 0xdeadbeef;

    auto lambda = [&]
    {
        __asm {

            mov eax, x
            mov y, eax
        }
    };

    lambda();
    return y;
}

오류를 방지하려면 다음 예제와 같이 어셈블리 코드를 명명된 함수로 이동합니다.To avoid the error, move the assembly code into a named function as shown in the following example:

#include <cstdio>

void g(int& x, int& y)
{
    __asm {
        mov eax, x
        mov y, eax
    }
}

int f()
{
    int y = 1724;
    int x = 0xdeadbeef;
    auto lambda = [&]
    {
        g(x, y);
    };
    lambda();
    return y;
}

int main()
{
    std::printf("%d\n", f());
}

반복기 디버깅 및 std::move_iteratorIterator debugging and std::move_iterator

반복기 디버깅 기능이 std::move_iterator를 적절하게 래핑 해제하도록 학습되었습니다.The iterator debugging feature has been taught to properly unwrap std::move_iterator. 예를 들어 std::copy(std::move_iterator<std::vector<int>::iterator>, std::move_iterator<std::vector<int>::iterator>, int*)는 이제 memcpy 빠른 경로에 참여할 수 있습니다.For example, std::copy(std::move_iterator<std::vector<int>::iterator>, std::move_iterator<std::vector<int>::iterator>, int*) can now engage the memcpy fast path.

<xkeycheck.h> 키워드 적용 수정Fixes for <xkeycheck.h> keyword enforcement

키워드 적용 <xkeycheck.h>를 대체하는 표준 라이브러리의 매크로가 일반 메시지 대신 검색된 실제 문제 키워드를 내보내도록 수정되었습니다.The standard library’s macro replacing a keyword enforcement <xkeycheck.h> was fixed to emit the actual problem keyword detected rather than a generic message. 또한 C++20 키워드를 지원하고 IntelliSense를 속여 임의의 키워드를 매크로로 가리키는 것을 방지합니다.It also supports C++20 keywords, and avoids tricking IntelliSense into saying random keywords are macros.

더 이상 사용되지 않는 할당자 형식Allocator types no longer deprecated

std::allocator<void>, std::allocator::size_type, std::allocator::difference_type은 더 이상 사용되지 않습니다.std::allocator<void>, std::allocator::size_type, and std::allocator::difference_type are no longer deprecated.

문자열 변환을 좁히기 위한 올바른 경고Correct warning for narrowing string conversions

표준에서 요청되지 않았으며, C4244 축소 경고가 표시되지 않도록 하는 의사 static_caststd::string에서 제거되었습니다.A spurious static_cast not called for by the standard that accidentally suppressed C4244 narrowing warnings was removed from std::string. 이제 std::string::string(const wchar_t*, const wchar_t*)를 호출하려고 하면 C4244 "wchar_t를 char로 축소합니다." 를 적절히 내보냅니다.Attempting to call std::string::string(const wchar_t*, const wchar_t*) will now properly emit C4244 "narrowing a wchar_t into a char."

다양한 <filesystem> 정확성 수정Various <filesystem> correctness fixes

  • 디렉터리의 마지막 쓰기 시간을 변경하려고 할 때 std::filesystem::last_write_time 오류가 수정되었습니다.Fixed std::filesystem::last_write_time failing when attempting to change a directory’s last write time.
  • 존재하지 않는 대상 경로를 제공할 때 std::filesystem::directory_entry 생성자는 이제 예외를 throw하는 대신 실패한 결과를 저장합니다.The std::filesystem::directory_entry constructor now stores a failed result, rather than throwing an exception, when supplied a nonexistent target path.
  • existing_p가 symlink인 경우 기본 CreateDirectoryExW 함수가 copy_symlink를 사용하므로 std::filesystem::create_directory 2-매개 변수 버전이 1-매개 변수 버전을 호출하도록 변경되었습니다.The std::filesystem::create_directory 2-parameter version was changed to call the 1-parameter version, as the underlying CreateDirectoryExW function would use copy_symlink when the existing_p was a symlink.
  • 손상된 symlink가 발견될 때 std::filesystem::directory_iterator에서 더 이상 오류가 발생하지 않습니다.std::filesystem::directory_iterator no longer fails when a broken symlink is found.
  • std::filesystem::space는 이제 상대 경로를 허용합니다.std::filesystem::space now accepts relative paths.
  • std::filesystem::path::lexically_relativeLWG 3096으로 보고된 후행 슬래시로 더 이상 혼동하지 않습니다.std::filesystem::path::lexically_relative is no longer confused by trailing slashes, reported as LWG 3096.
  • std::filesystem::create_symlink에서 슬래시가 있는 경로를 거부하는 CreateSymbolicLinkW를 해결했습니다.Worked around CreateSymbolicLinkW rejecting paths with forward slashes in std::filesystem::create_symlink.
  • Windows 10 LTSB 1609에 존재하지만 실제로 파일을 삭제할 수 없는 POSIX 삭제 모드 delete 함수가 해결되었습니다.Worked around the POSIX deletion mode delete function existing on Windows 10 LTSB 1609 but not actually being able to delete files.
  • std::boyer_moore_searcherstd::boyer_moore_horspool_searcher의 복사 생성자 및 복사 할당 연산자는 이제 실제로 항목을 복사합니다.std::boyer_moore_searcher and std::boyer_moore_horspool_searcher's copy constructors and copy assignment operators now actually copy things.

Windows 8 이상의 병렬 알고리즘Parallel algorithms on Windows 8 and later

병렬 알고리즘 라이브러리는 이제 Windows 7 및 이전 가짜 버전을 항상 사용하는 대신 Windows 8 이상에서 실제 WaitOnAddress 제품군을 올바르게 사용합니다.The parallel algorithms library now properly uses the real WaitOnAddress family on Windows 8 and later, rather than always using the Windows 7 and earlier fake versions.

std::system_category::message() 공백std::system_category::message() whitespace

std::system_category::message()는 이제 반환된 메시지에서 후행 공백을 삭제합니다.std::system_category::message() now trims trailing whitespace from the returned message.

std::linear_congruential_engine 0으로 나누기std::linear_congruential_engine divide by zero

std::linear_congruential_engine이 0으로 나누도록 트리거하는 일부 조건이 수정되었습니다.Some conditions that would cause std::linear_congruential_engine to trigger divide by 0 have been fixed.

반복기 래핑 해제를 위한 수정Fixes for iterator unwrapping

C++ 팀 블로그 문서 STL Features and Fixes in VS 2017 15.8(VS 2017 15.8의 STL 기능 및 수정 사항)에 설명된 대로 Visual Studio 2017 15.8에서 프로그래머와 사용자 통합을 위해 처음 공개된 반복기 래핑 해제 동작은 표준 라이브러리 반복기에서 파생된 반복기를 더 이상 래핑 해제하지 않습니다.The iterator unwrapping machinery that was first exposed for programmer-user integration in Visual Studio 2017 15.8, as described in C++ Team Blog article STL Features and Fixes in VS 2017 15.8, no longer unwraps iterators derived from standard library iterators. 예를 들어 std::vector<int>::iterator에서 파생되고 동작을 사용자 지정하려는 사용자는 이제 포인터의 동작 대신 표준 라이브러리 알고리즘을 호출할 때 사용자 지정된 동작을 가져옵니다.For example, a user that derives from std::vector<int>::iterator and tries to customize behavior now gets their customized behavior when calling standard library algorithms, rather than the behavior of a pointer.

순서가 지정되지 않은 컨테이너 reserve 함수가 이제 LWG 2156에 설명된 대로 N개 요소를 실제로 예약합니다.The unordered container reserve function now actually reserves for N elements, as described in LWG 2156.

시간 처리Time handling

  • 이전에는 동시성 라이브러리에 전달된 일부 시간 값이 오버플로되었습니다(예: condition_variable::wait_for(seconds::max())).Previously, some time values that were passed to the concurrency library would overflow, for example, condition_variable::wait_for(seconds::max()). 현재 수정된 이 오버플로는 임의의 29일 주기로 동작을 변경했습니다(기본 Win32 API에서 허용된 uint32_t 밀리초가 오버플로된 경우).Now fixed, the overflows changed behavior on a seemingly random 29-day cycle (when uint32_t milliseconds accepted by underlying Win32 APIs overflowed).

  • 이제 <ctime> 헤더가 전역 네임스페이스에서 선언하는 것 외에 std 네임스페이스에서도 timespectimespec_get을(를) 올바르게 선언합니다.The <ctime> header now correctly declares timespec and timespec_get in namespace std in addition to declaring them in the global namespace.

컨테이너에 대한 다양한 수정Various fixes for containers

  • 향상된 IntelliSense 환경을 위해 프라이빗으로 설정된 표준 라이브러리 내부 컨테이너 함수가 많습니다.Many standard library internal container functions have been made private for an improved IntelliSense experience. 이후 MSVC 릴리스에서는 멤버를 프라이빗으로 표시하기 위한 추가 수정이 예상됩니다.Additional fixes to mark members as private are expected in later releases of MSVC.

  • list, mapunordered_map과 같은 노드 기반 컨테이너가 손상되는 예외 안전 정확성 문제가 해결되었습니다.Exception safety correctness problems wherein the node-based containers like list, map, and unordered_map would become corrupted were fixed. propagate_on_container_copy_assignment 또는 propagate_on_container_move_assignment 재할당 작업 중에 컨테이너의 sentinel 노드를 이전 할당자로 해제하고 이전 할당자를 통해 POCCA/POCMA 할당을 수행한 다음, 새 할당자에서 sentinel 노드를 가져오려고 시도합니다.During a propagate_on_container_copy_assignment or propagate_on_container_move_assignment reassignment operation, we would free the container’s sentinel node with the old allocator, do the POCCA/POCMA assignment over the old allocator, and then try to acquire the sentinel node from the new allocator. 이 할당에 실패하면 컨테이너가 손상되었지만, sentinel 노드 소유가 고정된 하드 데이터 구조이기 때문에 컨테이너를 제거할 수도 없었습니다.If this allocation failed, the container was corrupted and couldn’t even be destroyed, as owning a sentinel node is a hard data structure invariant. 이 코드가 기존 sentinel 노드를 제거하기 전에 소스 컨테이너의 할당자에서 새 sentinel 노드를 할당하도록 수정되었습니다.This code was fixed to allocate the new sentinel node from the source container’s allocator before destroying the existing sentinel node.

  • 컨테이너는 is_always_equal로 선언된 할당자에 대해서도 propagate_on_container_copy_assignment, propagate_on_container_move_assignmentpropagate_on_container_swap에 따라 할당자를 항상 복사/이동/스왑하도록 수정되었습니다.The containers were fixed to always copy/move/swap allocators according to propagate_on_container_copy_assignment, propagate_on_container_move_assignment, and propagate_on_container_swap, even for allocators declared is_always_equal.

  • P0083 "맵 및 집합 스플라이스"에 따라 rvalue 컨테이너를 허용하는 컨테이너 병합 및 추출 멤버 함수에 대한 오버로드 추가Added the overloads for container merge and extract member functions that accept rvalue containers per P0083 "Splicing Maps And Sets"

\r\n => \n의 std::basic_istream::read 처리std::basic_istream::read processing of \r\n => \n

std::basic_istream::read가 \r\n => \n 처리 과정에서 일시적으로 제공된 버퍼 파트에 쓰지 않도록 수정되었습니다.std::basic_istream::read was fixed to not write into parts of the supplied buffer temporarily as part of \r\n => \n processing. 이 변경으로 인해 Visual Studio 2017 15.8에서 4K보다 큰 읽기에 대해 얻은 성능 향상이 일부 손실됩니다.This change gives up some of the performance advantage that was gained in Visual Studio 2017 15.8 for reads larger than 4K in size. 하지만 문자당 3회의 가상 호출 방지를 통한 효율성 향상은 유지됩니다.However, efficiency improvements from avoiding three virtual calls per character are still present.

std::bitset 생성자std::bitset constructor

std::bitset 생성자는 큰 비트 세트에 대해 더 이상 1과 0을 역순으로 읽지 않습니다.The std::bitset constructor no longer reads the ones and zeroes in reverse order for large bitsets.

std::pair::operator= 재발std::pair::operator= regression

LWG 2729 "Missing SFINAE on std::pair::operator=";를 구현할 때 도입된 std::pair의 할당 연산자의 회귀가 수정되었습니다.Fixed a regression in std::pair's assignment operator introduced when implementing LWG 2729 "Missing SFINAE on std::pair::operator=";. 이제 std::pair로 변환할 수 있는 형식을 다시 올바르게 허용합니다.It now correctly accepts types convertible to std::pair again.

add_const_t에 대해 추론되지 않은 컨텍스트Non-deduced contexts for add_const_t

add_const_t 및 관련 함수가 추론되지 않은 컨텍스트로 간주되는 부 형식 특성 버그를 수정했습니다.Fixed a minor type traits bug, where add_const_t and related functions are supposed to be a non-deduced context. 즉, add_const_tconst T가 아니라 typename add_const<T>::type의 별칭이어야 합니다.In other words, add_const_t should be an alias for typename add_const<T>::type, not const T.

16.2의 버그 수정 및 동작 변경Bug fixes and behavior changes in 16.2

연관 컨테이너에 대한 Const 비교 연산자Const comparators for associative containers

코드 크기 축소를 위해 set, map, multisetmultimap에 검색 및 삽입을 위한 코드가 병합되었습니다.Code for search and insertion in set, map, multiset, and multimap has been merged for reduced code size. 이제 삽입 작업은 검색 작업이 이전에 수행한 것과 동일한 방식으로 const 비교 함수에서 보다 작음 비교를 호출합니다.Insertion operations now call the less-than comparison on a const comparison functor, in the same way that search operations have done previously. 다음 코드는 Visual Studio 2019 버전 16.1 이전 버전에서 컴파일되지만 Visual Studio 2019 버전 16.2에서 C3848을 생성합니다.The following code compiles in Visual Studio 2019 version 16.1 and earlier, but raises C3848 in Visual Studio 2019 version 16.2:

#include <iostream>
#include <map>

using namespace std;

struct K
{
   int a;
   string b = "label";
};

struct Comparer  {
   bool operator() (K a, K b) {
      return a.a < b.a;
   }
};

map<K, double, Comparer> m;

K const s1{1};
K const s2{2};
K const s3{3};

int main() {

   m.emplace(s1, 1.08);
   m.emplace(s2, 3.14);
   m.emplace(s3, 5.21);

}

오류를 방지하려면 비교 연산자 const를 설정합니다.To avoid the error, make the comparison operator const:

struct Comparer  {
   bool operator() (K a, K b) const {
      return a.a < b.a;
   }
};

Visual Studio 2017 RTW(버전 15.0)의 규칙 향상Conformance improvements in Visual Studio 2017 RTW (version 15.0)

집계를 위한 일반화된 constexpr 및 NSDMI(비정적 데이터 멤버 초기화) 지원이 추가되면서, 이제 Visual Studio 2017의 Microsoft C++ 컴파일러는 C++14 표준에 추가된 기능을 완벽하게 갖췄습니다.With support for generalized constexpr and non-static data member initialization (NSDMI) for aggregates, the Microsoft C++ compiler in Visual Studio 2017 is now complete for features added in the C++14 standard. 하지만 C++11 및 C++98 표준의 몇 가지 기능은 아직 컴파일러에 구현되지 않았습니다.However, the compiler still lacks a few features from the C++11 and C++98 standards. 컴파일러의 현재 상태를 보여 주는 테이블은 Microsoft C++ 언어 규칙 테이블을 참조하세요.See Microsoft C++ language conformance table for a table that shows the current state of the compiler.

C++11: 더 많은 라이브러리의 SFINAE 식 지원C++11: Expression SFINAE support in more libraries

Visual C++ 컴파일러는 decltypeconstexpr 식이 템플릿 매개 변수로 나타날 수 있는 템플릿 인수 감소 및 대체에 필요한 SFINAE 식에 대한 지원을 계속 개선하고 있습니다.The compiler continues to improve its support for expression SFINAE, which is required for template argument deduction and substitution where decltype and constexpr expressions may appear as template parameters. 자세한 내용은 Expression SFINAE improvements in Visual Studio 2017 RC(Visual Studio 2017 RC의 SFINAE 식 향상)를 참조하세요.For more information, see Expression SFINAE improvements in Visual Studio 2017 RC.

C++14: 집계용 NSDMIC++14: NSDMI for Aggregates

집계는 사용자 제공 생성자가 없고, 개인 또는 보호된 비정적 데이터 멤버가 없고, 기본 클래스가 없고, 가상 함수가 없는 배열 또는 클래스입니다.An aggregate is an array or a class with no user-provided constructor, no private or protected non-static data members, no base classes, and no virtual functions. C++14부터 집계에 멤버 이니셜라이저가 포함될 수 있습니다.Beginning in C++14 aggregates may contain member initializers. 자세한 내용은 Member initializers and aggregates(멤버 이니셜라이저 및 집계)를 참조하세요.For more information, see Member initializers and aggregates.

C++14: 확장된 constexprC++14: Extended constexpr

constexpr로 선언된 식은 이제 특정 종류의 선언, if 및 switch 문, loop 문 및 수명이 constexpr 식 계산 내에서 시작된 개체의 변형을 포함할 수 있습니다.Expressions declared as constexpr are now allowed to contain certain kinds of declarations, if and switch statements, loop statements, and mutation of objects whose lifetime began within the constexpr expression evaluation. 또한 더 이상 constexpr 비정적 멤버 함수가 암시적으로 const가 될 필요가 없습니다.Also, there is no longer a requirement that a constexpr non-static member function must be implicitly const. 자세한 내용은 Relaxing constraints on constexpr functions(constexpr 함수에 대한 제약 조건 완화)를 참조하세요.For more information, see Relaxing constraints on constexpr functions.

C++17: 간결한 static_assertC++17: Terse static_assert

static_assert용 메시지 매개 변수는 선택 사항입니다.the message parameter for static_assert is optional. 자세한 내용은 Extending static_assert, v2(static_assert 확장, v2)를 참조하세요.For more information, see Extending static_assert, v2.

C++17: [[fallthrough]] 특성C++17: [[fallthrough]] attribute

/std:c++17 모드에서 [[fallthrough]] 특성은 switch 문의 컨텍스트에서 제어 이동 동작이 의도된 컴파일러에 대한 힌트로 사용될 수 있습니다.In /std:c++17 mode, the [[fallthrough]] attribute can be used in the context of switch statements as a hint to the compiler that the fall-through behavior is intended. 이 특성을 사용하면 컴파일러가 이러한 경우에 경고를 실행하지 않습니다.This attribute prevents the compiler from issuing warnings in such cases. 자세한 내용은 Wording for [[fallthrough]] attribute([[fallthrough]] 특성의 표현)를 참조하세요.For more information, see Wording for [[fallthrough]] attribute.

일반화된 범위 기반 for 루프Generalized range-based for loops

범위 기반 for 루프에 동일한 형식의 begin()end() 반환 개체가 더 이상 필요하지 않습니다.Range-based for loops no longer require that begin() and end() return objects of the same type. 이 변경으로 인해 end()range-v3 및 완료되었지만 아직 게시되지 않은 범위 기술 사양의 범위에서 사용된 sentinel을 반환할 수 있습니다.This change enables end() to return a sentinel as used by ranges in range-v3 and the completed-but-not-quite-published Ranges Technical Specification. 자세한 내용은 Generalizing the Range-Based For Loop(범위 기반 for 루프 일반화)를 참조하세요.For more information, see Generalizing the Range-Based For Loop.

15.3의 규칙 향상Conformance improvements in 15.3

constexpr 람다constexpr lambdas

이제 상수 식에서 람다 식을 사용할 수 있습니다.Lambda expressions may now be used in constant expressions. 자세한 내용은 C++의 constexpr 람다 식을 참조하세요.For more information, see constexpr lambda expressions in C++.

함수 템플릿의 if constexprif constexpr in function templates

함수 템플릿에 컴파일 시간 분기가 가능하도록 if constexpr 문이 포함될 수 있습니다.A function template may contain if constexpr statements to enable compile-time branching. 자세한 내용은 if constexpr 문을 참조하세요.For more information, see if constexpr statements.

이니셜라이저를 사용하는 선택 문Selection statements with initializers

if 문은 문 자체 내의 블록 범위에서 변수를 소개하는 이니셜라이저를 포함할 수 있습니다.An if statement may include an initializer that introduces a variable at block scope within the statement itself. 자세한 내용은 이니셜라이저가 있는 if 문을 참조하세요.For more information, see if statements with initializer.

[[maybe_unused]][[nodiscard]] 특성[[maybe_unused]] and [[nodiscard]] attributes

새 특성 [[maybe_unused]]는 엔터티가 사용되지 않는 경우 경고를 해제합니다.New attribute [[maybe_unused]] silences warnings when an entity isn't used. [[nodiscard]] 특성은 함수 호출의 반환 값이 무시되는 경우 경고를 만듭니다.The [[nodiscard]] attribute creates a warning if the return value of a function call is discarded. 자세한 내용은 C++ 특성을 참조하세요.For more information, see Attributes in C++.

반복 없이 특성 네임스페이스 사용Using attribute namespaces without repetition

특성 목록에서 단일 네임스페이스 식별자만 사용하는 새 구문입니다.New syntax to enable only a single namespace identifier in an attribute list. 자세한 내용은 C++ 특성을 참조하세요.For more information, see Attributes in C++.

구조적 바인딩Structured bindings

이제 값이 배열, std::tuple 또는 std::pair이거나 모두 공용 비정적 데이터 멤버만 포함하는 경우 단일 선언에서 구성 요소의 값을 개별 이름으로 저장할 수 있습니다.It's now possible in a single declaration to store a value with individual names for its components, when the value is an array, a std::tuple or std::pair, or has all public non-static data members. 자세한 내용은 구조적 바인딩함수에서 여러 값 반환을 참조하세요.For more information, see Structured Bindings and Returning multiple values from a function.

열거형 클래스 값에 대한 생성 규칙Construction rules for enum class values

이제 해당 정의에서 열거자를 소개하지 않고 소스에서 목록 초기화 구문을 사용하는 경우 범위가 지정된 열거형의 기본 형식에서 열거형 자체로의 암시적/비축소 변환 기능이 있습니다.There's now an implicit/non-narrowing conversion from a scoped enumeration's underlying type to the enumeration itself, when its definition introduces no enumerator and the source uses a list-initialization syntax. 자세한 내용은 enum 클래스 값의 생성 규칙열거형을 참조하세요.For more information, see Construction Rules for enum class Values and Enumerations.

값 기준 *this 캡처Capturing *this by value

람다 식의 *this 개체는 이제 값을 기준으로 캡처할 수 있습니다.The *this object in a lambda expression may now be captured by value. 이 변경으로 인해 특히 최신 머신 아키텍처에서 병렬 및 비동기 작업을 통해 람다가 호출되는 시나리오를 사용할 수 있습니다.This change enables scenarios in which the lambda is invoked in parallel and asynchronous operations, especially on newer machine architectures. 자세한 내용은 Lambda Capture of *this by Value as [=,*this]([=,*this]로 값 기준 this 람다 캡처)를 참조하세요.For more information, see Lambda Capture of *this by Value as [=,*this].

bool에 대해 operator++ 제거Removing operator++ for bool

operator++는 더 이상 bool 형식에서 지원되지 않습니다.operator++ is no longer supported on bool types. 자세한 내용은 사용되지 않는 operator++(bool) 제거(영문)를 참조하세요.For more information, see Remove Deprecated operator++(bool).

사용되지 않는 register 키워드 제거Removing deprecated register keyword

이전에 더 이상 사용되지 않고(컴파일러에서 무시된) register 키워드가 이제 언어에서 제거되었습니다.The register keyword, previously deprecated (and ignored by the compiler), is now removed from the language. 자세한 내용은 사용되지 않는 register 키워드 제거(영문)를 참조하세요.For more information, see Remove Deprecated Use of the register Keyword.

15.5의 규칙 향상Conformance improvements in 15.5

[14]로 표시된 기능은 /std:c++14 모드에서도 무조건 사용할 수 있습니다.Features marked with [14] are available unconditionally even in /std:c++14 mode.

extern constexpr을 위한 새로운 컴파일러 스위치New compiler switch for extern constexpr

이전 버전의 Visual Studio에서는 constexpr 변수에 extern이 표시된 경우에도 컴파일러가 항상 해당 변수에 내부 연결을 제공했습니다.In earlier versions of Visual Studio, the compiler always gave a constexpr variable internal linkage even when the variable was marked extern. Visual Studio 2017 15.5 버전에서 새 컴파일러 스위치/Zc:externConstexpr는 올바른 표준 준수 동작을 활성화합니다.In Visual Studio 2017 version 15.5, a new compiler switch, /Zc:externConstexpr, enables correct standards-conforming behavior. 자세한 내용은 extern constexpr 링크를 참조하세요.For more information, see extern constexpr linkage.

동적 예외 사양 제거Removing dynamic exception specifications

P0003R5 C++11에서는 동적 예외 사양이 사용되지 않았습니다.P0003R5 Dynamic exception specifications were deprecated in C++11. 이 기능은 C++17에서 제거되었지만 사용되지 않는 throw() 사양이 여전히 noexcept(true)의 별칭으로 엄격히 유지됩니다.the feature is removed from C++17, but the (still) deprecated throw() specification is kept strictly as an alias for noexcept(true). 자세한 내용은 동적 예외 사양 제거 및 noexcept를 참조하세요.For more information, see Dynamic exception specification removal and noexcept.

not_fn()

P0005R4 not_fnnot1not2를 대체합니다.P0005R4 not_fn is a replacement of not1 and not2.

enable_shared_from_this 표현 수정Rewording enable_shared_from_this

C++11에서 P0033R1 enable_shared_from_this가 추가되었습니다.P0033R1 enable_shared_from_this was added in C++11. C++17 표준은 비정상적인 특정 사례를 더 잘 처리하도록 사양을 업데이트합니다.The C++17 standard updates the specification to better handle certain corner cases. [14][14]

맵과 집합 스플라이스Splicing maps and sets

P0083R3 이 기능은 연관 컨테이너에서 map, set, unordered_map, unordered_set 등의 노드 추출을 지원하며, 추출된 노드는 수정한 뒤 동일한 컨테이너나 동일한 노드 형식을 사용하는 다른 컨테이너에 다시 삽입할 수 있습니다.P0083R3 This feature enables extraction of nodes from associative containers (that is, map, set, unordered_map, unordered_set) which can then be modified and inserted back into the same container or a different container that uses the same node type. (일반적인 사용 사례는 std::map에서 노드를 추출하고 키를 변경하고 다시 삽입하는 것입니다.)(A common use case is to extract a node from a std::map, change the key, and reinsert.)

남아 있는 라이브러리 파트 사용 중단Deprecating vestigial library parts

P0174R2 C++ 표준 라이브러리의 몇 가지 기능은 여러 해 동안 새로운 기능으로 대체되었거나, 유용하지 않거나 문제가 있는 것으로 확인되었습니다.P0174R2 Several features of the C++ standard library have been superseded by newer features over the years, or else have been found not useful, or problematic. 이러한 기능은 공식적으로 C++17에서 사용되지 않습니다.These features are officially deprecated in C++17.

std::function에서 할당자 지원 제거Removing allocator support in std::function

P0302R1 C++17 이전에는 클래스 템플릿 std::function에 할당자 인수를 사용하는 몇 가지 생성자가 있었습니다.P0302R1 Prior to C++17, the class template std::function had several constructors that took an allocator argument. 그러나 이 컨텍스트에서 할당자를 사용하는 것이 문제가 되었고, 의미 체계는 불확실했습니다.However, the use of allocators in this context was problematic, and the semantics were unclear. 문제 생성자가 제거되었습니다.The problem contructors have been removed.

not_fn() 수정Fixes for not_fn()

P0358R1 std::not_fn의 표현이 래퍼 호출에 사용 시 값 범주의 전파가 지원됨을 나타내도록 수정되었습니다.P0358R1 New wording for std::not_fn provides support of propagation of value category when used in wrapper invocation.

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

P0414R2 라이브러리 기본 사항에서 C++17로 shared_ptr 변경 사항 병합.P0414R2 Merging shared_ptr changes from Library Fundamentals to C++17. [14][14]

배열에 대한 shared_ptr 수정Fixing shared_ptr for arrays

P0497R0 배열에 대한 shared_ptr 지원 해결입니다.P0497R0 Fixes to shared_ptr support for arrays. [14][14]

insert_return_type의 명확한 정의Clarifying insert_return_type

P0508R0 고유한 키가 포함된 연관 컨테이너와 고유한 키가 포함된 불규칙 컨테이너에는 중첩 형식 insert_return_type을 반환하는 멤버 함수 insert가 있습니다.P0508R0 The associative containers with unique keys, and the unordered containers with unique keys have a member function insert that returns a nested type insert_return_type. 이 반환 형식은 이제 컨테이너의 반복기와 노드 형식에서 매개 변수화되는 형식의 특수화로 정의됩니다.That return type is now defined as a specialization of a type that is parameterized on the Iterator and NodeType of the container.

표준 라이브러리의 인라인 변수Inline variables for the standard library

P0607R0P0607R0

부록 D 기능 사용 중단Annex D features deprecated

C++ 표준의 부록 D에는 사용이 중단된 모든 기능이 포함되어 있습니다(shared_ptr::unique(), <codecvt>namespace std::tr1 포함).Annex D of the C++ standard contains all the features that have been deprecated, including shared_ptr::unique(), <codecvt>, and namespace std::tr1. /std:c++17 컴파일러 스위치를 설정하면 부록 D의 거의 모든 표준 라이브러리 기능이 사용되지 않는 것으로 표시됩니다.When the /std:c++17 compiler switch is set, almost all the standard library features in Annex D are marked as deprecated. 자세한 내용은 부록 D의 표준 라이브러리 기능이 사용되지 않는 것으로 표시됨을 참조하세요.For more information, see Standard library features in Annex D are marked as deprecated.

<experimental/filesystem>std::tr2::sys 네임스페이스는 이제 기본적으로 /std:c++14 하에서 사용 중단 경고를 생성하며, /std:c++17 하에서 기본적으로 제거됩니다.The std::tr2::sys namespace in <experimental/filesystem> now emits a deprecation warning under /std:c++14 by default, and is now removed under /std:c++17 by default.

비표준 확장(클래스 내 명시적 특수화)을 방지하여 <iostream>의 규칙이 개선되었습니다.Improved conformance in <iostream> by avoiding a non-standard extension (in-class explicit specializations).

이제 표준 라이브러리에서 변수 템플릿을 내부적으로 사용합니다.The standard library now uses variable templates internally.

형식 시스템의 noexcept 추가 및 dynamic-exception-specifications 제거를 포함한 C++17 컴파일러 변경 사항에 따라 표준 라이브러리가 업데이트되었습니다.The standard library has been updated in response to C++17 compiler changes, including the addition of noexcept in the type system and the removal of dynamic-exception-specifications.

15.6의 규칙 향상Conformance improvements in 15.6

C++17 라이브러리 기본 사항 V1C++17 Library Fundamentals V1

P0220R1은 C++17에 대한 라이브러리 기본 사항 기술 사양을 표준으로 통합합니다.P0220R1 incorporates Library Fundamentals Technical Specification for C++17 into the standard. <experimental/tuple>, <experimental/optional>, <experimental/functional>, <experimental/any>, <experimental/string_view>, <experimental/memory>, <experimental/memory_resource> 및 <experimental/algorithm>의 업데이트를 다룹니다.Covers updates to <experimental/tuple>, <experimental/optional>, <experimental/functional>, <experimental/any>, <experimental/string_view>, <experimental/memory>, <experimental/memory_resource>, and <experimental/algorithm>.

C++17: 표준 라이브러리의 클래스 템플릿 인수 추론 향상C++17: Improving class template argument deduction for the standard library

P0739R0 adopt_lock_tscoped_lock에 대한 매개 변수 목록의 앞으로 이동하여 scoped_lock의 일관된 사용을 활성화합니다.P0739R0 Move adopt_lock_t to front of parameter list for scoped_lock to enable consistent use of scoped_lock. 복사 할당을 사용할 수 있도록 std::variant 생성자가 더 많은 사례에서 오버로드 해결에 참여하도록 허용합니다.Allow std::variant constructor to participate in overload resolution in more cases, to enable copy assignment.

15.7의 규칙 향상Conformance improvements in 15.7

C++17: 상속 생성자 표현 수정C++17: Rewording inheriting constructors

P0136R1 생성자의 이름을 지정하는 using 선언에서 이제 파생 클래스 생성자를 추가로 선언하는 대신 파생 클래스의 초기화에 해당 기본 클래스 생성자가 표시되도록 합니다.P0136R1 specifies that a using declaration that names a constructor now makes the corresponding base class constructors visible to initializations of the derived class, rather than declaring additional derived class constructors. 이 표현 수정은 C++14의 변경 내용입니다.This rewording is a change from C++14. Visual Studio 2017 버전 15.7 이상의 /std:c++17 모드에서는, C++14에서 유효하고 상속 생성자를 사용하는 코드가 유효하지 않거나 다른 의미 체계를 가질 수 있습니다.In Visual Studio 2017 version 15.7 and later, in /std:c++17 mode, code that is valid in C++14 and uses inheriting constructors may not be valid, or may have different semantics.

다음 예제에서는 C++14 동작을 보여 줍니다.The following example shows C++14 behavior:

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).

다음 예제에서는 Visual Studio 15.7에서 /std:c++17 동작을 보여 줍니다.The following example shows /std:c++17 behavior in Visual Studio 15.7:

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)

자세한 내용은 생성자를 참조하세요.For more information, see Constructors.

C++17: 확장된 집계 초기화C++17: Extended aggregate initialization

P0017R1P0017R1

기본 클래스의 생성자가 공용이 아니지만 파생된 클래스에 액세스할 수 있는 경우 Visual Studio version 15.7의 /std:c++17 모드에서 파생된 형식의 개체를 초기화하기 위해 더 이상 빈 중괄호를 사용할 수 없습니다.If the constructor of a base class is non-public, but accessible to a derived class, then under /std:c++17 mode in Visual Studio version 15.7 you can no longer use empty braces to initialize an object of the derived type.

다음 예제에서는 C++14 준수 동작을 보여 줍니다.The following example shows C++14 conformant behavior:

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에서 Derived는 이제 집계 형식으로 간주되므로In C++17, Derived is now considered an aggregate type. 프라이빗 기본 생성자를 통한 Base의 초기화가 확장된 집계 초기화 규칙의 일부로 직접 발생합니다.It means that the initialization of Base via the private default constructor happens directly, as part of the extended aggregate initialization rule. 이전에는 Base 프라이빗 생성자가 Derived 생성자를 통해 호출되었으며, friend 선언 때문에 성공했습니다.Previously, the Base private constructor was called via the Derived constructor, and it succeeded because of the friend declaration.

다음 예제에서는 /std:c++17 모드의 Visual Studio 버전 15.7에서 C++17 동작을 보여 줍니다.The following example shows C++17 behavior in Visual Studio version 15.7 in /std:c++17 mode:

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: 자동으로 비형식 템플릿 매개 변수 선언C++17: Declaring non-type template parameters with auto

P0127R2P0127R2

/std:c++17 모드에서 컴파일러는 이제 자동으로 선언된 비형식 템플릿 인수의 형식을 추론할 수 있습니다.In /std:c++17 mode, the compiler can now deduce the type of a non-type template argument that is declared with auto:

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

이 새로운 기능의 한가지 영향은 유효한 C++14 코드는 유효하지 않을 수 있거나 서로 다른 의미 체계를 가질 수 있다는 것입니다.One impact of this new feature is that valid C++14 code may not be valid or may have different semantics. 예를 들어 이전에 유효하지 않았던 일부 오버로드가 이제 유효합니다.For example, some overloads that were previously invalid are now valid. 다음 예제에서는 example(p)에 대한 호출이 example(void*);로 바인딩되기 때문에 컴파일하는 C++14 코드를 보여 줍니다.The following example shows C++14 code that compiles because the call to example(p) is bound to example(void*);. Visual Studio 2017 버전 15.7의 /std:c++17 모드에서 example 함수 템플릿은 가장 일치하는 것입니다.In Visual Studio 2017 version 15.7, in /std:c++17 mode, the example function template is the best match.

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
}

다음 예제에서는 /std:c++17 모드의 Visual Studio 15.7에서 C++17 코드를 보여 줍니다.The following example shows C++17 code in Visual Studio 15.7 in /std:c++17 mode:

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: 기본 문자열 변환(부분)C++17: Elementary string conversions (partial)

P0067R5 정수와 문자열 간 및 부동 소수점 숫자와 문자열 간의 전환에 대한 하위 수준, 로캘 무관 함수입니다.P0067R5 Low-level, locale-independent functions for conversions between integers and strings and between floating-point numbers and strings.

C++20: 불필요한 decay 방지(부분)C++20: Avoiding unnecessary decay (partial)

P0777R1 "decay"의 개념과 const 또는 참조 한정자의 단순한 제거 간의 차이를 추가합니다.P0777R1 Adds differentiation between the concept of "decay" and that of simply removing const or reference qualifiers. 새 형식 특성 remove_reference_t는 일부 컨텍스트에서 decay_t를 대체합니다.New type trait remove_reference_t replaces decay_t in some contexts. remove_cvref_t 지원은 Visual Studio 2019에서 구현되었습니다.Support for remove_cvref_t is implemented in Visual Studio 2019.

C++17: 병렬 알고리즘C++17: Parallel algorithms

P0024R2 병렬 처리 TS는 약간의 수정으로 표준으로 통합됩니다.P0024R2 The Parallelism TS is incorporated into the standard, with minor modifications.

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

P0030R1 각각 세 개의 입력 매개 변수를 갖는 float, doublelong double 형식에 대해 std::hypot로 세 개의 새로운 오버로드를 추가합니다.P0030R1 Adds three new overloads to std::hypot, for types float, double, and long double, each of which has three input parameters.

C++17: <filesystem>C++17: <filesystem>

P0218R1 몇 가지 단어 수정으로 파일 시스템 TS를 표준으로 채택합니다.P0218R1 Adopts the File System TS into the standard with a few wording modifications.

C++17: 수학 특수 함수C++17: Mathematical special functions

P0226R1 수학 특수 함수에 대한 이전 기술 사양을 표준 <cmath> 헤더로 채택합니다.P0226R1 Adopts previous technical specifications for Mathematical Special Functions into the standard <cmath> header.

C++17: 표준 라이브러리에 대한 추론 가이드C++17: Deduction guides for the standard library

P0433R2 클래스 탬플릿 인수 추론에 대한 지원을 추가하는 P0091R3의 C++17 도입의 이점을 활용하기 위해 STL로 업데이트합니다.P0433R2 Updates to STL to take advantage of C++17 adoption of P0091R3, which adds support for class template argument deduction.

C++17: 기본 문자열 변환 복구C++17: Repairing elementary string conversions

P0682R1 P0067R5의 새 기본 문자열 변환 기능에서 새 헤더 <charconv>로 이동하고 std::error_code 대신 std::errc를 사용하여 오류 처리 변경을 포함하는 다른 개선 사항을 만듭니다.P0682R1 Move the new elementary string conversion functions from P0067R5 into a new header <charconv> and make other improvements, including changing error handling to use std::errc instead of std::error_code.

C++17: char_traits에 대한 constexpr(부분)C++17: constexpr for char_traits (partial)

P0426R1 상수 식에서 std::string_view를 사용할 수 있도록 std::traits_type 멤버 함수 length, comparefind를 변경합니다.P0426R1 Changes to std::traits_type member functions length, compare, and find to make std::string_view usable in constant expressions. (Visual Studio 2017 버전 15.6에서 Clang/LLVM에 대해서만 지원됩니다.(In Visual Studio 2017 version 15.6, supported for Clang/LLVM only. 버전 15.7 미리 보기 2에서 ClXX에 대해서도 지원이 거의 완료되었습니다.)In version 15.7 Preview 2, support is nearly complete for ClXX as well.)

15.9의 규칙 향상Conformance improvements in 15.9

->*, [], >>, << 연산자의 왼쪽에서 오른쪽 계산 순서Left-to-right evaluation order for operators ->*, [], >>, and <<

C++17부터 ->*, [], >>, << 연산자의 피연산자가 왼쪽에서 오른쪽 순으로 계산되어야 합니다.Starting in C++17, the operands of the operators ->*, [], >>, and << must be evaluated in left-to-right order. 컴파일러가 이 순서를 보장할 수 없는 두 가지 경우는 다음과 같습니다.There are two cases in which the compiler is unable to guarantee this order:

  • 피연산자 식 중 하나가 값으로 전달된 개체이거나 값으로 전달된 개체를 포함하는 경우, 또는when one of the operand expressions is an object passed by value or contains an object passed by value, or

  • /clr을 사용하여 컴파일할 때 피연산자 중 하나가 개체 또는 배열 요소의 필드인 경우.when compiled by using /clr, and one of the operands is a field of an object or an array element.

컴파일러는 왼쪽에서 오른쪽으로 계산을 보장할 수 없는 경우 경고 C4866을 생성합니다.The compiler emits warning C4866 when it can't guarantee left-to-right evaluation. 이러한 연산자의 왼쪽에서 오른쪽 순서 요구 사항이 C++17에서 도입되었기 때문에, /std:c++17 이상을 지정한 경우에만 컴파일러에서 이 경고를 생성합니다.The compiler generates this warning only if /std:c++17 or later is specified, as the left-to-right order requirement of these operators was introduced in C++17.

이 경고를 해결하려면 먼저 피연산자 계산으로 순서에 종속되는 부작용이 발생하는 경우처럼 피연산자의 왼쪽에서 오른쪽으로 계산이 필요한지 고려합니다.To resolve this warning, first consider whether left-to-right evaluation of the operands is necessary, such as when evaluation of the operands might produce order-dependent side-effects. 대부분의 경우 피연산자가 계산되는 순서는 눈에 띄는 영향을 미치지 않습니다.In many cases, the order in which operands are evaluated has no observable effect. 계산 순서가 왼쪽에서 오른쪽이어야 하는 경우, 대신 const 참조로 피연산자를 전달할 수 있는지 여부를 고려합니다.If the order of evaluation must be left-to-right, consider whether you can pass the operands by const reference instead. 이렇게 변경하면 다음 코드 샘플에서 경고가 제거됩니다.This change eliminates the warning in the following code sample:

// 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>>
};

Visual Studio 2017 RTW(버전 15.0)의 버그 수정Bug fixes in Visual Studio 2017 RTW (version 15.0)

Copy-list-initializationCopy-list-initialization

Visual Studio 2017에서는 Visual Studio 2015에서 catch되지 않았으며 크래시나 정의되지 않은 런타임 동작을 일으킬 수 있었던, 이니셜라이저 목록을 사용한 개체 만들기와 관련된 컴파일러 오류를 올바르게 발생시킵니다.Visual Studio 2017 correctly raises compiler errors related to object creation using initializer lists that were not caught in Visual Studio 2015, and could lead to crashes or undefined runtime behavior. N4594 13.3.1.7p1을 기준으로, copy-list-initialization에서 컴파일러는 오버로드 해결을 위해 명시적 생성자를 고려해야 하지만 이 특정 오버로드가 선택되면 오류를 발생시켜야 합니다.As per N4594 13.3.1.7p1, in copy-list-initialization, the compiler is required to consider an explicit constructor for overload resolution, but must raise an error if that particular overload is chosen.

다음 두 가지 예제는 Visual Studio 2015에서 컴파일되지만 Visual Studio 2017에서 컴파일되지 않습니다.The following two examples compile in Visual Studio 2015 but not in Visual Studio 2017.

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 &'

}

오류를 수정하려면 직접 초기화를 사용합니다.To correct the error, use direct initialization:

A a1{ 1 };
const A& a2{ 1 };

Visual Studio 2015에서 컴파일러는 일반 copy-initialization과 같은 방식으로 copy-list-initialization을 잘못 처리했고 오버로드 확인을 위해 생성자 변환만 고려했습니다.In Visual Studio 2015, the compiler erroneously treated copy-list-initialization in the same way as regular copy-initialization; it considered only converting constructors for overload resolution. 다음 예제에서 Visual Studio 2015에서는 MyInt(23)를 선택하지만 Visual Studio 2017에서는 정확히 오류를 발생시킵니다.In the following example, Visual Studio 2015 chooses MyInt(23) but Visual Studio 2017 correctly raises the error.

// 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
}

이 예제는 이전 예제와 비슷하지만 다른 오류를 발생시킵니다.This example is similar to the previous one but raises a different error. 이 예제는 Visual Studio 2015에서는 성공하지만 Visual Studio 2017(C2668 포함)에서는 실패합니다.It succeeds in Visual Studio 2015 and fails in Visual Studio 2017 with C2668.

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
}

사용되지 않는 형식 정의Deprecated typedefs

Visual Studio 2017에서는 이제 클래스 또는 구조체에서 선언된 사용되지 않는 형식 정의에 대한 올바른 경고를 실행합니다.Visual Studio 2017 now issues the correct warning for deprecated typedefs that are declared in a class or struct. 다음 예제는 Visual Studio 2015에서는 경고 없이 컴파일되지만 Visual Studio 2017에서는 C4996를 생성합니다.The following example compiles without warnings in Visual Studio 2015 but produces C4996 in Visual Studio 2017.

struct A
{
    // also for __declspec(deprecated)
    [[deprecated]] typedef int inttype;
};

int main()
{
    A::inttype a = 0; // C4996 'A::inttype': was declared deprecated
}

constexprconstexpr

Visual Studio 2017에서는 조건부 계산 연산의 왼쪽 피연산자가 constexpr 컨텍스트에서 유효하지 않을 경우 올바르게 오류를 발생시킵니다.Visual Studio 2017 correctly raises an error when the left-hand operand of a conditionally evaluating operation isn't valid in a constexpr context. 다음 코드는 Visual Studio 2017이 아닌 Visual Studio 2015에서 컴파일합니다(C3615 constexpr 함수 ‘f’는 상수 식이 될 수 없음).The following code compiles in Visual Studio 2015 but not in Visual Studio 2017 (C3615 constexpr function 'f' cannot result in a constant expression):

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
}

오류를 수정하려면 array::size() 함수를 constexpr로 선언하거나 f에서 constexpr 한정자를 제거합니다.To correct the error, either declare the array::size() function as constexpr or remove the constexpr qualifier from f.

variadic 함수에 전달된 클래스 형식Class types passed to variadic functions

Visual Studio 2017에서 printf와 같이 variadic 함수에 전달된 클래스 또는 구조체는 일반적으로 복사 가능합니다.In Visual Studio 2017, classes or structs that are passed to a variadic function such as printf must be trivially copyable. 해당 개체를 전달할 때 컴파일러는 비트 복사본을 만들기만 하고 생성자 또는 소멸자를 호출하지 않습니다.When passing such objects, the compiler simply makes a bitwise copy and doesn't call the constructor or destructor.

#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
}

오류를 수정하려면 일반적으로 복사 가능한 형식을 반환하는 멤버 함수를 호출하거나To correct the error, you can call a member function that returns a trivially copyable type,

    std::atomic<int> i(0);
    printf("%i\n", i.load());

정적 캐스트를 사용하여 개체를 변환한 후 전달합니다.or else use a static cast to convert the object before passing it:

    struct S {/* as before */} s(0);
    printf("%i\n", static_cast<int>(s))

CString을 사용하여 빌드 및 관리되는 문자열의 경우 제공된 operator LPCTSTR()를 사용하여 CString 개체를 서식 문자열에 필요한 C 포인터에 캐스트해야 합니다.For strings built and managed using CString, the provided operator LPCTSTR() should be used to cast a CString object to the C pointer expected by the format string.

CString str1;
CString str2 = _T("hello!");
str1.Format(_T("%s"), static_cast<LPCTSTR>(str2));

클래스 생성의 cv 한정자Cv-qualifiers in class construction

Visual Studio 2015에서는 컴파일러가 생성자 호출을 통해 클래스 개체를 생성할 때 cv 한정자를 잘못 무시하는 경우가 있습니다.In Visual Studio 2015, the compiler sometimes incorrectly ignores the cv-qualifier when generating a class object via a constructor call. 이 문제로 인해 잠재적으로 크래시 또는 예기치 않은 런타임 동작이 발생할 수 있습니다.This issue can potentially cause a crash or unexpected runtime behavior. 다음 예제는 Visual Studio 2015에서는 컴파일되지만 Visual Studio 2017에서는 컴파일러 오류를 발생시킵니다.The following example compiles in Visual Studio 2015 but raises a compiler error in Visual Studio 2017:

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

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

오류를 수정하려면 operator int()const로 선언합니다.To correct the error, declare operator int() as const.

템플릿의 정규화된 이름에 대한 액세스 검사Access checking on qualified names in templates

이전 버전의 컴파일러는 일부 템플릿 컨텍스트에서 정규화된 이름에 대한 액세스를 검사하지 않았습니다.Previous versions of the compiler did not check access to qualified names in some template contexts. 이 문제는 이름에 액세스할 수 없어 대체에 실패할 것으로 예상되는 경우의 SFINAE 동작을 방해할 수 있습니다.This issue can interfere with expected SFINAE behavior where the substitution is expected to fail because of the inaccessibility of a name. 컴파일러가 연산자의 틀린 오버로드를 잘못 호출했기 때문에 잠재적으로 런타임에 크래시나 예기치 않은 동작이 발생할 수 있었습니다.It could have potentially caused a crash or unexpected behavior at runtime because the compiler incorrectly called the wrong overload of the operator. Visual Studio 2017에서는 컴파일러 오류가 발생합니다.In Visual Studio 2017, a compiler error is raised. 구체적인 오류는 달라질 수 있지만 일반적으로 오류는 “C2672 일치하는 오버로드된 함수가 없습니다.”입니다.The specific error might vary, but typically it's "C2672 no matching overloaded function found". 다음 코드는 Visual Studio 2015에서는 컴파일되지만 Visual Studio 2017에서는 오류를 발생시킵니다.The following code compiles in Visual Studio 2015 but raises an error in Visual Studio 2017:

#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.
}

누락된 템플릿 인수 목록Missing template argument lists

Visual Studio 2015 및 이전 버전에서는 템플릿이 기본 템플릿 인수 또는 비형식 템플릿 매개 변수의 일부 등으로 템플릿 매개 변수 목록에 표시될 때 컴파일러가 누락된 템플릿 인수 목록을 진단하지 않았습니다.In Visual Studio 2015 and earlier, the compiler did not diagnose missing template argument lists when the template appeared in a template parameter list, for example, as part of a default template argument or a non-type template parameter. 이 문제로 인해 컴파일러 크래시나 예기치 않은 런타임 동작을 포함하여 예기치 않은 동작이 발생할 수 있습니다.This issue can result in unpredictable behavior, including compiler crashes or unexpected runtime behavior. 다음 코드는 Visual Studio 2015에서 컴파일되지만 Visual Studio 2017에서는 오류를 생성합니다.The following code compiles in Visual Studio 2015, but produces an error in Visual Studio 2017.

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;

SFINAE 식Expression-SFINAE

SFINAE 식을 지원하기 위해 이제 컴파일러는 템플릿이 인스턴스화가 아니라 선언될 때 decltype 인수를 구문 분석합니다.To support expression-SFINAE, the compiler now parses decltype arguments when the templates are declared rather than instantiated. 따라서 decltype 인수에 비종속 특수화가 있는 경우 이 특수화는 인스턴스화 시점까지 지연되지 않고Consequently, if a non-dependent specialization is found in the decltype argument, it's not deferred to instantiation-time. 즉시 처리되며, 모든 결과 오류가 그 시점에 진단됩니다.It's processed immediately, and any resulting errors are diagnosed at that time.

다음 예제에서는 선언 시점에 발생한 컴파일러 오류를 보여 줍니다.The following example shows such a compiler error that is raised at the point of declaration:

#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");

익명 네임스페이스에 선언된 클래스Classes declared in anonymous namespaces

C++ 표준에 따라 익명 네임스페이스 내에 선언된 클래스는 내부 연결이 있으므로 내보낼 수 없습니다.According to the C++ standard, a class declared inside an anonymous namespace has internal linkage, and that means it can't be exported. Visual Studio 2015 및 이전 버전에서는 이 규칙이 적용되지 않았습니다.In Visual Studio 2015 and earlier, this rule wasn't enforced. Visual Studio 2017에서는 이 규칙이 부분적으로 적용됩니다.In Visual Studio 2017, the rule is partially enforced. 다음 예제에서는 Visual Studio 2017에서 "오류 C2201: const anonymous namespace::S1::vftable: 가져오거나 내보내려면 외부 링크가 있어야 합니다." 오류를 발생시킵니다.The following example raises this error in Visual Studio 2017: "error C2201: const anonymous namespace::S1::vftable: must have external linkage in order to be exported/imported."

struct __declspec(dllexport) S1 { virtual void f() {} }; //C2201

값 클래스 멤버에 대한 기본 이니셜라이저(C++/CLI)Default initializers for value class members (C++/CLI)

Visual Studio 2015 이하에서는 컴파일러가 값 클래스 멤버에 대한 기본 멤버 이니셜라이저를 허용하지만 무시했습니다.In Visual Studio 2015 and earlier, the compiler permitted (but ignored) a default member initializer for a member of a value class. 값 클래스의 기본 초기화는 항상 멤버를 0으로 초기화합니다.Default initialization of a value class always zero-initializes the members. 기본 생성자는 허용되지 않습니다.A default constructor isn't permitted. Visual Studio 2017에서는 기본 멤버 이니셜라이저가 이 예제에 표시된 대로 컴파일러 오류를 발생시킵니다.In Visual Studio 2017, default member initializers raise a compiler error, as shown in this example:

value struct V
{
    int i = 0; // error C3446: 'V::i': a default member initializer
               // isn't allowed for a member of a value class
};

기본 인덱서(C++/CLI)Default indexers (C++/CLI)

Visual Studio 2015 이하에서는 컴파일러가 기본 속성을 기본 인덱서로 잘못 식별하는 경우가 있었습니다.In Visual Studio 2015 and earlier, the compiler in some cases misidentified a default property as a default indexer. 속성에 액세스하는 데 식별자 default를 사용하여 문제를 해결할 수 있었습니다.It was possible to work around the issue by using the identifier default to access the property. default가 C++11에서 키워드로 도입된 이후 해결 방법 자체가 문제가 되었습니다.The workaround itself became problematic after default was introduced as a keyword in C++11. Visual Studio 2017에서는 해결 방법이 필요했던 버그가 수정되었고 이제 컴파일러는 default가 클래스에 대한 기본 속성에 액세스하는 데 사용될 경우 오류를 발생시킵니다.In Visual Studio 2017, the bugs that required the workaround were fixed, and the compiler now raises an error when default is used to access the default property for a class.

//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에서는 이름을 사용하여 값 속성에 둘 다 액세스할 수 있습니다.In Visual Studio 2017, you can access both Value properties by their name:

#using "class1.dll"

void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2)
{
       r1->Value;
       r2->Value;
}

15.3의 버그 수정Bug fixes in 15.3

삭제된 멤버 템플릿에 대한 호출Calls to deleted member templates

이전 버전의 Visual Studio에서는 컴파일러가 런타임에 크래시를 일으킬 수 있는, 삭제된 멤버 템플릿에 대한 잘못된 양식의 호출에 대한 오류를 내보내지 못하는 경우가 있었습니다.In previous versions of Visual Studio, the compiler in some cases would fail to emit an error for ill-formed calls to a deleted member template that would have potentially caused crashes at runtime. 다음 코드는 C2280 "'int S<int>::f<int>(void)': 삭제된 함수를 참조하려고 합니다."를 생성합니다.The following code now produces C2280, "'int S<int>::f<int>(void)': attempting to reference a deleted function":

template<typename T>
struct S {
   template<typename U> static int f() = delete;
};

void g()
{
   decltype(S<int>::f<int>()) i; // this should fail
}

오류를 수정하려면 iint로 선언합니다.To fix the error, declare i as int.

형식 특성에 대한 전제 조건 검사Pre-condition checks for type traits

Visual Studio 2017 버전 15.3에서는 표준을 더 엄격하게 따르도록 형식 특성에 대한 전제 조건 검사가 향상되었습니다.Visual Studio 2017 version 15.3 improves pre-condition checks for type-traits to more strictly follow the standard. 해당 검사는 할당 가능합니다.One such check is for assignable. 다음 코드는 Visual Studio 2017 버전 15.3에서 C2139를 생성합니다.The following code produces C2139 in Visual Studio 2017 version 15.3:

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

네이티브에서 관리로의 마샬링에 대한 새로운 컴파일러 경고 및 런타임 검사New compiler warning and runtime checks on native-to-managed marshaling

관리형 함수에서 네이티브 함수로 호출하려면 마샬링이 필요합니다.Calling from managed functions to native functions requires marshaling. CLR은 마샬링을 수행하지만 C++ 의미 체계를 이해하지 못합니다.The CLR does the marshaling, but it doesn't understand C++ semantics. 네이티브 개체를 값으로 전달하면 CLR은 개체의 복사 생성자를 호출하거나, 런타임에 정의되지 않은 동작을 유발할 수 있는 BitBlt를 사용합니다.If you pass a native object by value, CLR either calls the object's copy-constructor or uses BitBlt, which may cause undefined behavior at runtime.

이제 컴파일러는 컴파일 시간에 삭제된 복사 생성자를 포함하는 네이티브 개체가 네이티브 경계와 관리되는 경계 사이에 값으로 전달됨을 알 수 있는 경우 경고를 내보냅니다.Now the compiler emits a warning if it can know at compile time that a native object with deleted copy ctor is passed between native and managed boundary by value. 컴파일러는 컴파일 시간에 알 수 없는 이러한 경우를 위해 잘못된 양식의 마양샬링이 수행될 때 프로그램에서 즉시 std::terminate를 호출하도록 런타임 검사를 삽입합니다.For those cases in which the compiler doesn't know at compile time, it injects a runtime check so that the program calls std::terminate immediately when an ill-formed marshaling occurs. Visual Studio 2017 15.3에서 다음 코드는 경고 C4606을 생성합니다. "'A': 네이티브 및 관리 경계에서 인수를 값별로 전달하려면 유효한 복사 생성자가 필요합니다.In Visual Studio 2017 version 15.3, the following code produces warning C4606 "'A': passing argument by value across native and managed boundary requires valid copy constructor. 이 생성자가 없으면 런타임 동작이 정의되지 않습니다.”Otherwise, the runtime behavior is undefined.

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()
{
    f(A()); // This call from managed to native requires marshaling. The CLR doesn't understand C++ and uses BitBlt, which results in a double-free later.
}

오류를 수정하려면 #pragma managed 지시문을 제거하여 호출자를 네이티브로 표시하고 마샬링을 방지합니다.To fix the error, remove the #pragma managed directive to mark the caller as native and avoid marshaling.

WinRT에 대한 실험적 API 경고Experimental API warning for WinRT

실험 및 피드백용으로 릴리스된 WinRT API는 Windows.Foundation.Metadata.ExperimentalAttribute로 데코레이트됩니다.WinRT APIs that are released for experimentation and feedback are decorated with Windows.Foundation.Metadata.ExperimentalAttribute. Visual Studio 2017 버전 15.3에서는 컴파일러에서 특성을 발견하면 C4698 경고를 생성합니다.In Visual Studio 2017 version 15.3, the compiler produces warning C4698 when it encounters the attribute. 이전 Windows SDK 버전의 몇몇 API는 이미 특성으로 데코레이트되었고 이러한 API를 호출하면 이제 이 컴파일러 경고가 트리거됩니다.A few APIs in previous versions of the Windows SDK have already been decorated with the attribute, and calls to these APIs now trigger this compiler warning. 최신 Windows SDK에서는 모든 제공된 형식에서 이 특성이 제거되었지만, 이전 SDK를 사용 중인 경우 모든 제공된 형식 호출에 대해 이러한 경고가 표시되지 않도록 해야 합니다.Newer Windows SDKs have the attribute removed from all shipped types, but if you're using an older SDK, you'll need to suppress these warnings for all calls to shipped types.

다음 코드는 경고 C4698을 생성합니다. “‘Windows::Storage::IApplicationDataStatics2::GetForUserAsync’는 평가 목적으로만 제공되며 향후 업데이트에서 변경되거나 제거될 수 있습니다.”The following code produces warning C4698: "'Windows::Storage::IApplicationDataStatics2::GetForUserAsync' is for evaluation purposes only and is subject to change or removal in future updates":

Windows::Storage::IApplicationDataStatics2::GetForUserAsync(); //C4698

이 경고를 사용하지 않도록 설정하려면 #pragma를 추가합니다.To disable the warning, add a #pragma:

#pragma warning(push)
#pragma warning(disable:4698)

Windows::Storage::IApplicationDataStatics2::GetForUserAsync();

#pragma warning(pop)

템플릿 멤버 함수의 확장 정의Out-of-line definition of a template member function

Visual Studio 2017 버전 15.3에서는 클래스에 선언되지 않은 템플릿 멤버 함수의 확장 정의를 발견할 경우 오류를 생성합니다.Visual Studio 2017 version 15.3 produces an error when it encounters an out-of-line definition of a template member function that wasn't declared in the class. 다음 코드는 오류 C2039를 생성합니다. ‘f’:이 ‘S’의 멤버가 아닙니다.The following code now produces error C2039: 'f': is not a member of 'S':

struct S {};

template <typename T>
void S::f(T t) {} //C2039: 'f': is not a member of 'S'

오류를 해결하려면 클래스에 선언을 추가합니다.To fix the error, add a declaration to the class:

struct S {
    template <typename T>
    void f(T t);
};
template <typename T>
void S::f(T t) {}

this 포인터의 주소 사용 시도Attempting to take the address of this pointer

C++에서 this는 X에 대한 형식 포인터의 prvalue입니다. this 의 주소를 가져오거나 lvalue 참조에 바인딩할 수 없습니다.In C++ this is a prvalue of type pointer to X. You can't take the address of this or bind it to an lvalue reference. 이전 버전의 Visual Studio에서는 컴파일러를 통해 캐스트를 사용하여 이 제한 사항을 회피할 수 있었습니다.In previous versions of Visual Studio, the compiler would allow you to circumvent this restriction by use of a cast. Visual Studio 2017 버전 15.3에서는 컴파일러에서 C2664 오류를 생성합니다.In Visual Studio 2017 version 15.3, the compiler produces error C2664.

액세스할 수 없는 기본 클래스로의 변환Conversion to an inaccessible base class

Visual Studio 2017 버전 15.3에서 형식을 액세스할 수 없는 기본 클래스로 변환하려고 하면 오류가 발생합니다.Visual Studio 2017 version 15.3 produces an error when you attempt to convert a type to a base class that is inaccessible. 이제는 컴파일러에서 "오류 C2243: 'type cast': 변환('D *'에서 'B *'(으)로)이 있지만 액세스할 수 없습니다."를 발생시킵니다.The compiler now raises "error C2243: 'type cast': conversion from 'D *' to 'B *' exists, but is inaccessible". 다음 코드는 형식이 잘못되었고 런타임에 충돌을 일으킬 수 있습니다.The following code is ill-formed and can potentially cause a crash at runtime. 이제 컴파일러는 다음과 같은 코드를 발견할 때 C2243을 생성합니다.The compiler now produces C2243 when it encounters code like this:

#include <memory>

class B { };
class D : B { }; // C2243. should be public B { };

void f()
{
   std::unique_ptr<B>(new D());
}

기본 인수는 멤버 함수의 확장 정의에서 허용되지 않음Default arguments aren't allowed on out of line definitions of member functions

기본 인수는 템플릿 클래스에 있는 멤버 함수의 확장 정의에서 허용되지 않습니다.Default arguments aren't allowed on out-of-line definitions of member functions in template classes. 컴파일러는 /permissive 아래에 경고를 실행하고, /permissive- 아래에 하드 오류를 실행합니다.The compiler will issue a warning under /permissive, and a hard error under /permissive-.

이전 버전의 Visual Studio에서는 다음과 같은 잘못된 코드로 인해 잠재적으로 런타임 크래시가 발생할 수 있었습니다.In previous versions of Visual Studio, the following ill-formed code could potentially cause a runtime crash. Visual Studio 2017 버전 15.3은 경고 C5034를 생성합니다. 'A<T>::f': 클래스 템플릿 멤버의 확장 정의에는 기본 인수가 포함될 수 없습니다.Visual Studio 2017 version 15.3 produces warning C5034: 'A<T>::f': an out-of-line definition of a member of a class template cannot have default arguments:

template <typename T>
struct A {
    T f(T t, bool b = false);
};

template <typename T>
T A<T>::f(T t, bool b = false) // C5034
{
    // ...
}

오류를 해결하려면 = false 기본 인수를 제거합니다.To fix the error, remove the = false default argument.

복합 멤버 지정자와 함께 offsetof 사용Use of offsetof with compound member designator

Visual Studio 2017 버전 15.3에서 m이 "복합 멤버 지정자"인 offsetof(T, m)를 사용하면 /Wall 옵션으로 컴파일할 때 경고가 발생합니다.In Visual Studio 2017 version 15.3, using offsetof(T, m) where m is a "compound member designator" results in a warning when you compile with the /Wall option. 다음 코드는 형식이 잘못되었고 런타임에 크래시가 발생할 수 있습니다.The following code is ill-formed and could potentially cause a crash at runtime. Visual Studio 2017 버전 15.3에서 "경고 C4841: 비표준 확장이 사용됨: 복합 멤버 지정자가 offsetof에 사용되었습니다."를 생성합니다.Visual Studio 2017 version 15.3 produces "warning C4841: non-standard extension used: compound member designator in offsetof":

struct A {
   int arr[10];
};

// warning C4841: non-standard extension used: compound member designator in offsetof
constexpr auto off = offsetof(A, arr[2]);

코드를 수정하려면 pragma를 사용하여 경고를 사용하지 않도록 설정하거나 offsetof를 사용하지 않도록 코드를 변경합니다.To fix the code, either disable the warning with a pragma or change the code to not use offsetof:

#pragma warning(push)
#pragma warning(disable: 4841)
constexpr auto off = offsetof(A, arr[2]);
#pragma warning(pop)

정적 데이터 멤버 또는 멤버 함수와 함께 offsetof 사용Using offsetof with static data member or member function

Visual Studio 2017 버전 15.3에서 m이 정적 데이터 멤버 또는 멤버 함수를 참조하는 offsetof(T, m)를 사용하면 오류가 발생합니다.In Visual Studio 2017 version 15.3, using offsetof(T, m) where m refers to a static data member or a member function results in an error. 다음 코드는 “오류 C4597: 정의되지 않은 동작: offsetof가 멤버 함수 ‘example’에 적용되었습니다.” 및 “오류 C4597: 정의되지 않은 동작: offsetof가 정적 데이터 멤버 ‘sample’에 적용되었습니다.”를 생성합니다.The following code produces "error C4597: undefined behavior: offsetof applied to member function 'example'" and "error C4597: undefined behavior: offsetof applied to static data member 'sample'":

#include <cstddef>

struct A {
   int ten() { return 10; }
   static constexpr int two = 2;
};

constexpr auto off = offsetof(A, ten);
constexpr auto off2 = offsetof(A, two);

이 코드는 형식이 잘못되었고 런타임에 크래시가 발생할 수 있습니다.This code is ill-formed and could potentially cause a crash at runtime. 오류를 해결하려면 정의되지 않은 동작을 더 이상 호출하지 않도록 코드를 변경합니다.To fix the error, change the code to no longer invoke undefined behavior. C++ 표준에서 허용되지 않는, 포팅할 수 없는 코드입니다.It's non-portable code that's disallowed by the C++ standard.

__declspec 특성에 대한 새로운 경고New warning on __declspec attributes

Visual Studio 2017 버전 15.3에서는 __declspec(...)extern "C" 링크 사양 앞에 적용되면 컴파일러에서 더 이상 특성을 무시하지 않습니다.In Visual Studio 2017 version 15.3, the compiler no longer ignores attributes if __declspec(...) is applied before extern "C" linkage specification. 이전 버전에서는 컴파일러가 런타임 의미를 가질 수 있는 특성을 무시합니다.Previously, the compiler would ignore the attribute, which could have runtime implications. /Wall/WX 옵션이 설정되면 다음 코드는 “경고 C4768: 링크 사양 앞의 __declspec 특성은 무시됩니다.”를 생성합니다.When the /Wall and /WX options are set, the following code produces "warning C4768: __declspec attributes before linkage specification are ignored":

__declspec(noinline) extern "C" HRESULT __stdcall //C4768

경고를 수정하려면 extern "C"를 먼저 배치합니다.To fix the warning, put extern "C" first:

extern "C" __declspec(noinline) HRESULT __stdcall

이 경고는 15.3에서 기본적으로 꺼져 있지만 15.5에서는 기본적으로 켜져 있으며, /Wall /WX로 컴파일된 코드에만 영향을 줍니다.This warning is off by default in 15.3, but on by default in 15.5, and only impacts code compiled with /Wall /WX.

decltype 및 삭제된 소멸자 호출decltype and calls to deleted destructors

이전 버전의 Visual Studio에서 컴파일러는 삭제된 소멸자 호출이 decltype과 연결된 식의 컨텍스트에서 발생한 시점을 검색하지 않았습니다.In previous versions of Visual Studio, the compiler didn't detect when a call to a deleted destructor occurred in the context of the expression associated with decltype. Visual Studio 2017 버전 15.3에서 다음 코드는 "오류 C2280: 'A<T>::~A(void)': 삭제된 함수를 참조하려고 시도 중"을 생성합니다.In Visual Studio 2017 version 15.3, the following code produces "error C2280: 'A<T>::~A(void)': attempting to reference a deleted function":

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);
}

초기화되지 않은 const 변수Uninitialized const variables

Visual Studio 2017 RTW 릴리스에는 const 변수가 초기화되지 않은 경우 C++ 컴파일러가 진단을 실행하지 않는 재발 문제가 있었습니다.Visual Studio 2017 RTW release had a regression in which the C++ compiler wouldn't issue a diagnostic if a const variable wasn't initialized. 이 재발 문제는 Visual Studio 2017 버전 15.3에서 수정되었습니다.This regression has been fixed in Visual Studio 2017 version 15.3. 다음 코드는 이제 "경고 C4132: 'Value': const 개체를 초기화해야 합니다."를 생성합니다.The following code now produces "warning C4132: 'Value': const object should be initialized":

const int Value; //C4132

오류를 해결하려면 Value에 값을 할당합니다.To fix the error, assign a value to Value.

빈 선언Empty declarations

Visual Studio 2017 버전 15.3에서는 이제 기본 제공 형식이 아닌 모든 형식의 빈 선언에 대해 경고를 생성합니다.Visual Studio 2017 version 15.3 now warns on empty declarations for all types, not just built-in types. 다음 코드는 모든 네 가지 선언에 대한 수준 2 C4091 경고를 생성합니다.The following code now produces a level 2 C4091 warning for all four declarations:

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

경고를 제거하려면 빈 선언을 주석으로 처리하거나 제거합니다.To remove the warnings, comment-out or remove the empty declarations. 명명되지 않은 개체에 부작용(예: RAII)을 포함하려는 경우 개체에 이름을 지정해야 합니다.In cases where the unnamed object is intended to have a side effect (such as RAII), it should be given a name.

경고는 /Wv:18에서는 제외되고 기본적으로 경고 수준 W2에서 켜집니다.The warning is excluded under /Wv:18 and is on by default under warning level W2.

배열 형식에 대한 std::is_convertiblestd::is_convertible for array types

이전 버전의 컴파일러는 배열 형식에 대한 std::is_convertible에 대해 잘못된 결과를 제공했습니다.Previous versions of the compiler gave incorrect results for std::is_convertible for array types. 따라서 라이브러리 작성자는 std::is_convertible<...> 형식 특성을 사용할 때 특별히 Microsoft C++ 컴파일러를 사용해야 했습니다.This required library writers to special-case the Microsoft C++ compiler when using the std::is_convertible<...> type trait. 다음 예제에서는 정적 어설션이 이전 버전의 Visual Studio에서는 통과하지만 Visual Studio 2017 업데이트 버전 15.3에서는 실패합니다.In the following example, the static asserts pass in earlier versions of Visual Studio but fail in Visual Studio 2017 version 15.3:

#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>가 계산됩니다.std::is_convertible<From, To> is calculated by checking to see if an imaginary function definition is well formed:

   To test() { return std::declval<From>(); }

프라이빗 소멸자 및 std::is_constructiblePrivate destructors and std::is_constructible

이전 버전의 컴파일러에서는 std::is_constructible의 결과를 결정할 때 소멸자가 비공개인지 여부를 무시했습니다.Previous versions of the compiler ignored whether a destructor was private when deciding the result of std::is_constructible. 그러나 지금은 비공개 여부를 고려합니다.It now considers them. 다음 예제에서는 정적 어설션이 이전 버전의 Visual Studio에서는 통과하지만 Visual Studio 2017 업데이트 버전 15.3에서는 실패합니다.In the following example, the static asserts pass in earlier versions of Visual Studio but fail in Visual Studio 2017 version 15.3:

#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);

비공개 소멸자는 형식을 non-constructible로 만듭니다.Private destructors cause a type to be non-constructible. 다음 선언이 작성된 것처럼 std::is_constructible<T, Args...>가 계산됩니다.std::is_constructible<T, Args...> is calculated as if the following declaration were written:

   T obj(std::declval<Args>()...)

이 호출은 소멸자 호출을 의미합니다.This call implies a destructor call.

C2668: 모호한 오버로드 확인C2668: Ambiguous overload resolution

이전 버전의 컴파일러에서는 선언 및 인수 종속성 조회를 모두 사용하여 여러 후보를 찾을 때 모호성을 검색하지 못하는 경우가 종종 있었습니다.Previous versions of the compiler sometimes failed to detect ambiguity when it found multiple candidates via both using declarations and argument-dependent lookup. 이 오류로 인해 잘못된 오버로드를 선택하고 예기치 않은 런타임 동작이 발생할 수 있습니다.This failure can lead to the wrong overload being chosen, and to unexpected runtime behavior. 다음 예제에서는 Visual Studio 2017 버전 15.3에서 "C2668 'f': 오버로드된 함수에 대한 호출이 모호합니다."를 정확히 발생시킵니다.In the following example, Visual Studio 2017 version 15.3 correctly raises C2668 'f': ambiguous call to overloaded function:

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()를 호출하려는 경우 코드를 수정하려면 사용 중인 N::f 문을 제거합니다.To fix the code, remove the using N::f statement if you intended to call ::f().

C2660: 로컬 함수 선언 및 인수 종속성 조회C2660: local function declarations and argument-dependent lookup

로컬 함수 선언은 바깥쪽 범위에 있는 함수 선언을 숨기고 인수 종속성 조회를 사용하지 않도록 설정합니다.Local function declarations hide the function declaration in the enclosing scope and disable argument-dependent lookup. 그러나 이 경우에는 이전 버전의 컴파일러가 인수 종속성 조회를 수행했으므로 잘못된 오버로드를 선택하고 예기치 않은 런타임 동작이 발생할 가능성이 있습니다.However, previous versions of the compiler performed argument-dependent lookup in this case, potentially leading to the wrong overload being chosen and unexpected runtime behavior. 일반적으로 이 오류는 로컬 함수 선언의 잘못된 시그니처 때문입니다.Typically, the error is because of an incorrect signature of the local function declaration. 다음 예제에서는 Visual Studio 2017 버전 15.3이 “C2660 ‘f’: 함수는 2개의 매개 변수를 사용하지 않습니다.”를 올바르게 발생시킵니다.In the following example, Visual Studio 2017 version 15.3 correctly raises C2660 'f': function does not take two arguments:

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);
}

이 문제를 해결하려면 f(S) 시그니처를 변경하거나 제거합니다.To fix the problem, either change the f(S) signature or remove it.

C5038: 이니셜라이저 목록에서 초기화 순서C5038: order of initialization in initializer lists

클래스 멤버는 이니셜라이저 목록에 표시되는 순서가 아니라 선언된 순서대로 초기화됩니다.Class members are initialized in the order they're declared, not the order they appear in initializer lists. 이전 버전의 컴파일러는 이니셜라이저 목록의 순서가 선언 순서와 다른 경우 경고를 표시하지 않았습니다.Previous versions of the compiler didn't warn when the order of the initializer list differed from the order of declaration. 이 문제로 인해 한 멤버의 초기화가 이미 초기화되고 있는 목록의 다른 멤버에 종속된 경우 정의되지 않은 런타임 동작이 발생할 수 있었습니다.This issue could lead to undefined runtime behavior if the initialization of one member depended on another member in the list already being initialized. 다음 예제에서는 Visual Studio 2017 버전 15.3( /Wall 포함)에서 "C5038: 'A::y' 데이터 멤버가 'A::y' 데이터 멤버 다음에 초기화됩니다."라는 경고를 발생시킵니다.In the following example, Visual Studio 2017 version 15.3 (with /Wall) raises "warning C5038: data member 'A::y' will be initialized after data member 'A::x'":

struct A
{
    A(int a) : y(a), x(y) {} // Initialized in reverse, y reused
    int x;
    int y;
};

문제를 해결하려면 선언과 같은 순서가 되도록 이니셜라이저 목록을 정렬합니다.To fix the problem, arrange the initializer list to have the same order as the declarations. 하나 또는 두 이니셜라이저가 기본 클래스 구성원을 참조하는 경우 유사한 경고가 발생합니다.A similar warning is raised when one or both initializers refer to base class members.

이 경고는 기본적으로 꺼져 있으며, /Wall로 컴파일된 코드에만 영향을 줍니다.This warning is off-by-default, and only affects code compiled with /Wall.

15.5의 버그 수정 및 기타 동작 변경Bug fixes and other behavior changes in 15.5

부분 순서 변경Partial ordering change

컴파일러는 이제 다음 코드를 올바르게 거부하고 올바른 오류 메시지를 제공합니다.The compiler now correctly rejects the following code and gives the correct error message:

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*)'

위의 예에서 문제는 형식에 두 가지 차이점이 있다는 것입니다(const 및 non-const와 pack 및 non-pack).The problem in the example above is that there are two differences in the types (const vs. non-const and pack vs. non-pack). 컴파일러 오류를 제거하려면 차이점 중 하나를 제거합니다.To eliminate the compiler error, remove one of the differences. 이렇게 하면 컴파일러가 함수의 순서를 명확하게 지정할 수 있습니다.This enables the compiler to unambiguously order the functions.

template<typename... T>
int f(T* ...)
{
    return 1;
}

template<typename T>
int f(T&)
{
    return 2;
}

int main()
{
    int i = 0;
    f(&i);
}

예외 처리기Exception handlers

배열 또는 함수 형식에 대한 참조 처리기는 모든 예외 개체에 일치하지 않습니다.Handlers of reference to array or function type are never a match for any exception object. 컴파일러는 이제 이 규칙을 올바르게 적용하고 수준 4 경고를 생성합니다.The compiler now correctly honors this rule and raises a level 4 warning. 또한 /Zc:strictStrings가 사용될 경우 char* 또는 wchar_t* 처리기를 더 이상 문자열 리터럴에 일치시키지 않습니다.It also no longer matches a handler of char* or wchar_t* to a string literal when /Zc:strictStrings is used.

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

다음 코드에서는 오류를 방지합니다.The following code avoids the error:

catch (int (*)[1]) {}

std::tr1 네임스페이스가 사용되지 않음std::tr1 namespace is deprecated

이제 비표준 std::tr1 네임스페이스가 C++14 및 C++17 모드에서 모두 사용되지 않는 것으로 표시됩니다.The non-standard std::tr1 namespace is now marked as deprecated in both C++14 and C++17 modes. Visual Studio 2017 15.5 버전에서 다음 코드를 실행하면 C4996이 발생합니다.In Visual Studio 2017 version 15.5, the following code raises C4996:

#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.

이 오류를 해결하려면 tr1 네임스페이스에 대한 참조를 제거합니다.To fix the error, remove the reference to the tr1 namespace:

#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;
}

부록 D의 표준 라이브러리 기능이 사용되지 않는 것으로 표시됨Standard library features in Annex D are marked as deprecated

/std:c++17 모드 컴파일러 스위치를 설정하면 부록 D의 거의 모든 표준 라이브러리 기능이 사용되지 않는 것으로 표시됩니다.When the /std:c++17 mode compiler switch is set, almost all standard library features in Annex D are marked as deprecated.

Visual Studio 2017 15.5 버전에서 다음 코드를 실행하면 C4996이 발생합니다.In Visual Studio 2017 version 15.5, the following code raises C4996:

#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.

이 오류를 해결하려면 다음 코드에 설명된 것처럼 경고 텍스트의 지침을 따르세요.To fix the error, follow the instructions in the warning text, as demonstrated in the following code:

#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");

참조되지 않은 지역 변수Unreferenced local variables

Visual Studio 15.5에서는 다음 코드에 표시된 것처럼 C4189 경고가 더 많은 경우에 내보내집니다.In Visual Studio 15.5, warning C4189 is emitted in more cases, as shown in the following code:

void f() {
    char s[2] = {0}; // C4189. Either use the variable or remove it.
}
warning C4189: 's': local variable is initialized but not referenced

이 오류를 해결하려면 사용되지 않는 변수를 제거합니다.To fix the error, remove the unused variable.

한 줄로 된 주석Single-line comments

Visual Studio 2017 15.5 버전에서는 C 컴파일러에서 더 이상 C4001 및 C4179 경고를 내보내지 않습니다.In Visual Studio 2017 version 15.5, warnings C4001 and C4179 are no longer emitted by the C compiler. 이전에는 이러한 경고가 /Za 컴파일러 스위치하에서만 내보내졌습니다.Previously, they were only emitted under the /Za compiler switch. C99 이후로 한 줄로 된 주석이 C 표준에 포함되었으므로 이러한 경고는 더 이상 필요하지 않습니다.The warnings are no longer needed because single-line comments have been part of the C standard since C99.

/* 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'

코드가 이전 버전과 호환될 필요가 없는 경우 C4001/C4179 비표시 오류(Suppression)를 제거하여 경고를 방지할 수 있습니다.If the code doesn't need to be backwards compatible, you can avoid the warning by removing the C4001/C4179 suppression. 코드가 이전 버전과 호환되어야 할 경우 C4619만 표시되지 않게 합니다.If the code does need to be backward compatible, then suppress C4619 only.


/* C only */

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

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

extern "C" 연결이 있는 __declspec 특성__declspec attributes with extern "C" linkage

이전 버전의 Visual Studio에서는 extern "C" 링크 사양 앞에 __declspec(...) 가 적용된 경우 컴파일러가 __declspec(...) 특성을 무시했습니다.In earlier versions of Visual Studio, the compiler ignored __declspec(...) attributes when __declspec(...) was applied before the extern "C" linkage specification. 이 동작은 사용자가 의도하지 않은 코드 생성을 유발했으며 런타임에도 영향을 줄 가능성이 있었습니다.This behavior caused code to be generated that user didn't intend, with possible runtime implications. 이 경고는 Visual Studio 15.3 버전에서 추가되었지만 기본적으로 꺼져 있었습니다.The warning was added in Visual Studio version 15.3, but was off by default. Visual Studio 2017 15.5 버전에서 이 경고는 기본적으로 활성화되어 있습니다.In Visual Studio 2017 version 15.5, the warning is enabled by default.

__declspec(noinline) extern "C" HRESULT __stdcall //C4768
warning C4768: __declspec attributes before linkage specification are ignored

이 오류를 해결하려면 __declspec 특성 앞에 링크 사양을 추가하세요.To fix the error, place the linkage specification before the __declspec attribute:

extern "C" __declspec(noinline) HRESULT __stdcall

이 새로운 경고 C4768은 Visual Studio 2017 15.3 이하 버전과 함께 제공된 일부 Windows SDK 헤더에서 표시됩니다(예: RS2 SDK라고도 하는 10.0.15063.0 버전).This new warning C4768 is given on some Windows SDK headers that were shipped with Visual Studio 2017 15.3 or older (for example: version 10.0.15063.0, also known as RS2 SDK). 그러나 이후 버전의 Windows SDK 헤더(특히 ShlObj.h 및 ShlObj_core.h)는 이 경고를 생성하지 않도록 수정되었습니다.However, later versions of Windows SDK headers (specifically, ShlObj.h and ShlObj_core.h) have been fixed so that they don't produce the warning. Windows SDK 헤더에서 이 경고가 발생하면 이러한 작업을 수행할 수 있습니다.When you see this warning coming from Windows SDK headers, you can take these actions:

  1. Visual Studio 2017 버전 15.5 릴리스와 함께 제공된 최신 Windows SDK로 전환합니다.Switch to the latest Windows SDK that came with Visual Studio 2017 version 15.5 release.

  2. Windows SDK 헤더 문의 #include 주위에 있는 경고를 끕니다.Turn off the warning around the #include of the Windows SDK header statement:

   #pragma warning (push)
   #pragma warning(disable:4768)
   #include <shlobj.h>
   #pragma warning (pop)

extern constexpr 링크Extern constexpr linkage

이전 버전의 Visual Studio에서는 constexpr 변수에 extern이 표시된 경우에도 컴파일러가 항상 해당 변수에 내부 연결을 제공했습니다.In earlier versions of Visual Studio, the compiler always gave a constexpr variable internal linkage even when the variable was marked extern. Visual Studio 2017 15.5 버전에서 새 컴파일러 스위치( /Zc:externConstexpr)는 올바른 표준 준수 동작을 활성화합니다.In Visual Studio 2017 version 15.5, a new compiler switch (/Zc:externConstexpr) enables correct standards-conforming behavior. 결국 이 동작이 기본값이 됩니다.Eventually this behavior will become the default.

extern constexpr int x = 10;
error LNK2005: "int const x" already defined

헤더 파일에 extern constexpr로 선언된 변수가 포함되어 있으면 중복 선언을 올바르게 결합하기 위해 해당 변수에 __declspec(selectany)를 표시해야 합니다.If a header file contains a variable declared extern constexpr, it needs to be marked __declspec(selectany) to have its duplicate declarations combined correctly:

extern constexpr __declspec(selectany) int x = 10;

불완전한 클래스 형식에는 typeid를 사용할 수 없습니다.typeid can't be used on incomplete class type

이전 버전의 Visual Studio에서는 컴파일러가 다음 코드를 잘못 허용하여 형식 정보가 잘못될 가능성이 있었습니다.In earlier versions of Visual Studio, the compiler incorrectly allowed the following code, resulting in potentially incorrect type information. Visual Studio 2017 15.5 버전에서는 컴파일러에서 오류를 올바르게 생성합니다.In Visual Studio 2017 version 15.5, the compiler correctly raises an error:

#include <typeinfo>

struct S;

void f() { typeid(S); } //C2027 in 15.5
error C2027: use of undefined type 'S'

std::is_convertible 대상 유형std::is_convertible target type

std::is_convertible에서는 대상 유형이 유효한 반환 형식이어야 합니다.std::is_convertible requires the target type to be a valid return type. 이전 버전의 Visual Studio에서는 컴파일러가 추상 형식을 잘못 허용하여 오버로드 확인이 잘못되고 의도하지 않은 런타임 동작이 발생할 가능성이 있었습니다.In earlier versions of Visual Studio, the compiler incorrectly allowed abstract types, which might lead to incorrect overload resolution and unintended runtime behavior. 이제 다음 코드는 C2338을 올바르게 생성합니다.The following code now correctly raises C2338:

#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

오류를 방지하려면 is_convertible 사용 시 포인터 형식을 비교해야 합니다. 하나의 형식이 추상적일 경우 non-pointer-type 비교가 실패할 수 있기 때문입니다.To avoid the error, when using is_convertible you should compare pointer types because a non-pointer-type comparison might fail if one type is abstract:

#include <type_traits>

struct B { virtual ~B() = 0; };
struct D : public B { virtual ~D(); };

static_assert(std::is_convertible<D *, B *>::value, "fail");

동적 예외 사양 제거 및 noexceptDynamic exception specification removal and noexcept

C++17에서 throw()noexcept에 대한 별칭이고, throw(<type list>)throw(...)가 제거되었으며 특정 형식에 noexcept가 포함될 수 있습니다.In C++17, throw() is an alias for noexcept, throw(<type list>) and throw(...) are removed, and certain types may include noexcept. 이 변경으로 인해 C++14 또는 이전 버전을 준수하는 코드와 소스 호환성 문제가 발생할 수 있습니다.This change can cause source compatibility issues with code that conforms to C++14 or earlier. 전체적으로 C++17 모드를 사용 중일 때 /Zc:noexceptTypes- 스위치를 사용하여 noexcept 의 C++14 버전으로 되돌릴 수 있습니다.The /Zc:noexceptTypes- switch can be used to revert to the C++14 version of noexcept while using C++17 mode in general. 이렇게 하면 모든 throw() 코드를 동시에 다시 작성하지 않고도 C++17을 준수하도록 소스 코드를 업데이트할 수 있습니다.It enables you to update your source code to conform to C++17 without having to rewrite all your throw() code at the same time.

또한 컴파일러는 이제 새로운 경고 C5043과 관련하여 C++17 모드의 선언이나 /permissive-를 사용하여 더 많은 불일치 예외 사양을 진단합니다.The compiler also now diagnoses more mismatched exception specifications in declarations in C++17 mode or with /permissive- with the new warning C5043.

다음 코드는 Visual Studio 2017 버전 15.5에서 /std:c++17 스위치가 적용될 때 C5043 및 C5040을 생성합니다.The following code generates C5043 and C5040 in Visual Studio 2017 version 15.5 when the /std:c++17 switch is applied:

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
};

여전히 /std:c++17을 사용 중일 때 오류를 제거하려면 명령줄에 /Zc:noexceptTypes- 스위치를 추가하거나 다음 예제에 나와 있는 것처럼 noexcept를 사용하도록 코드를 업데이트하세요.To remove the errors while still using /std:c++17, either add the /Zc:noexceptTypes- switch to the command line, or else update your code to use noexcept, as shown in the following example:

void f() noexcept;
void f() noexcept { }
void g() noexcept(false);

struct A {
    virtual void f() noexcept;
};

struct B : A {
    virtual void f() noexcept { }
};

인라인 변수Inline variables

constexpr 정적 데이터 멤버는 이제 암시적으로 인라인이므로 이제 클래스 내 선언으로 정의됩니다.Static constexpr data members are now implicitly inline, which means that their declaration within a class is now their definition. constexpr 정적 데이터 멤버에 대한 확장 정의는 이제 중복되며 사용되지 않습니다.Using an out-of-line definition for a static constexpr data member is redundant, and now deprecated. Visual Studio 2017 버전 15.5에서 /std:c++17 스위치를 적용하면, 이제 다음 코드에서 경고 C5041 ‘‘size’: constexpr 정적 데이터 멤버에 대한 확장 정의는 C++17에서 필요하지 않거나 사용되지 않습니다.’가 발생합니다. In Visual Studio 2017 version 15.5, when the /std:c++17 switch is applied the following code now produces warning C5041 'size': out-of-line definition for constexpr static data member is not needed and is deprecated in C++17:

struct X {
    static constexpr int size = 3;
};
const int X::size; // C5041

extern "C" __declspec(...) 경고 C4768이 이제 기본적으로 켜짐extern "C" __declspec(...) warning C4768 now on by default

이 경고는 Visual Studio 2017 버전 15.3에서 추가되었지만 기본적으로 꺼져 있었습니다.The warning was added in Visual Studio 2017 version 15.3, but was off by default. Visual Studio 2017 버전 15.5에서는 이 경고가 기본적으로 켜집니다.In Visual Studio 2017 version 15.5, the warning is on by default. 자세한 내용은 __declspec 특성에 대한 새로운 경고를 참조하세요.For more information, see New warning on __declspec attributes.

기본값으로 설정된 함수 및 __declspec(nothrow)Defaulted functions and __declspec(nothrow)

컴파일러는 이전에 해당 기본/멤버 함수가 예외를 허용할 경우 기본값으로 설정된 함수를 __declspec(nothrow)로 선언하도록 허용했습니다.The compiler previously allowed defaulted functions to be declared with __declspec(nothrow) when the corresponding base/member functions permitted exceptions. 이 동작은 C++ 표준과 반대되며, 런타임 시 정의되지 않은 동작을 유발할 수 있습니다.This behavior is contrary to the C++ standard and can cause undefined behavior at runtime. 표준에 따라, 예외 사양 불일치가 있을 경우 이러한 함수를 삭제된 것으로 정의해야 합니다.The standard requires such functions to be defined as deleted if there's an exception specification mismatch. /std:c++17 하에서 다음 모드는 C2280 삭제된 함수를 참조하려고 합니다. 명시적 예외 사양이 암시적 선언의 명시적 예외 사양과 호환되지 않으므로 함수가 암시적으로 삭제되었습니다.’를 발생시킵니다.Under /std:c++17, the following code raises C2280 attempting to reference a deleted function. Function was implicitly deleted because the explicit exception specification is incompatible with that of the implicit declaration.

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
}

이 코드를 수정하려면 기본값으로 설정된 함수에서 __declspec(nothrow)를 제거하거나 = default를 제거하고 필요한 모든 예외 처리와 함께 함수에 대한 정의를 제공합니다.To correct this code, either remove __declspec(nothrow) from the defaulted function, or remove = default and provide a definition for the function along with any required exception handling:

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 및 부분 특수화noexcept and partial specializations

형식 시스템에서 noexcept를 사용하면 pointers-to-noexcept-functions에 대한 부분 특수화가 누락되어 일치하는 특정 “호출 가능” 형식이 컴파일되지 않거나 기본 템플릿을 선택하지 못할 수 있습니다.With noexcept in the type system, partial specializations for matching particular "callable" types may fail to compile or choose the primary template because of a missing partial specialization for pointers-to-noexcept-functions.

이러한 경우 noexcept 함수 포인터 및 멤버 함수에 대한 noexcept 포인터를 처리할 추가 부분 특수화를 추가해야 합니다.In such cases, you may need to add additional partial specializations to handle the noexcept function pointers and noexcept pointers to member functions. 이러한 오버로드는 /std:c++17 모드에서만 적합합니다.These overloads are only legal in /std:c++17 mode. C++14와 호환성을 유지해야 하고, 다른 사람이 사용할 코드를 작성 중인 경우 #ifdef 지시문 내에서 이러한 새 오버로드를 보호해야 합니다.If backwards-compatibility with C++14 must be maintained, and you're writing code that others consume, then you should guard these new overloads inside #ifdef directives. 자체 포함 모듈에서 작업 중인 경우 #ifdef 가드를 사용하는 대신 /Zc:noexceptTypes- 스위치를 사용하여 컴파일할 수 있습니다.If you're working in a self-contained module, then instead of using #ifdef guards you can just compile with the /Zc:noexceptTypes- switch.

다음 코드는 /std:c++14 하에서 컴파일하지만 "오류 C2027:정의되지 않은 형식 'A<T>'"와 함께 /std:c++17 하에서 실패합니다.The following code compiles under /std:c++14 but fails under /std:c++17 with "error C2027:use of undefined type 'A<T>'":

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
}

다음 코드는 컴파일러가 새로운 부분 특수화 A<void (*)() noexcept>를 선택하기 때문에 /std:c++17 하에서 성공합니다.The following code succeeds under /std:c++17 because the compiler chooses the new partial specialization 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.7의 버그 수정 및 기타 동작 변경Bug fixes and other behavior changes in 15.7

C++17: 기본 클래스 템플릿의 기본 인수C++17: Default argument in the primary class template

이 동작 변경은 클래스 템플릿에 대한 템플릿 인수 추론 - P0091R3의 사전 조건입니다.This behavior change is a precondition for Template argument deduction for class templates - P0091R3.

이전에는 컴파일러가 기본 클래스 템플릿의 기본 인수를 무시했습니다.Previously, the compiler ignored the default argument in the primary class template:

template<typename T>
struct S {
    void f(int = 0);
};

template<typename T>
void S<T>::f(int = 0) {} // Re-definition necessary

Visual Studio 2017 버전 15.7의 /std:c++17 모드에서는 기본 인수가 무시되지 않습니다.In /std:c++17 mode in Visual Studio 2017 version 15.7, the default argument isn't ignored:

template<typename T>
struct S {
    void f(int = 0);
};

template<typename T>
void S<T>::f(int) {} // Default argument is used

종속 이름 확인Dependent name resolution

이 동작 변경은 클래스 템플릿에 대한 템플릿 인수 추론 - P0091R3의 사전 조건입니다.This behavior change is a precondition for Template argument deduction for class templates - P0091R3.

다음 예제에서 Visual Studio 15.6 이하 버전의 컴파일러는 기본 클래스 템플릿에서 D::typeB<T>::type으로 확인합니다.In the following example, the compiler in Visual Studio 15.6 and earlier resolves D::type to B<T>::type in the primary class template.

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

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

Visual Studio 2017 버전 15.7의 /std:c++17 모드에서는 D의 using 문에 typename 키워드가 필요합니다. typename이 없으면 컴파일러가 경고 C4346: 'B<T*>::type': 종속 이름은 type이 아님 및 오류 C2061: 구문 오류: 식별자 'type' 을 발생시킵니다.Visual Studio 2017 version 15.7, in /std:c++17 mode, requires thetypename keyword in the using statement in D. Withouttypename, the compiler raises warning C4346: 'B<T*>::type': dependent name is not a type and error C2061: 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]] 특성 - 경고 수준 증가C++17: [[nodiscard]] attribute - warning level increase

Visual Studio 2017 버전 15.7의 /std:c++17 모드에서 C4834의 경고 레벨("'nodiscard' 특성이 포함된 함수의 반환 값을 버리는 중")은 W3에서 W1로 증가되었습니다.In Visual Studio 2017 version 15.7 in /std:c++17 mode, the warning level of C4834 ("discarding return value of function with 'nodiscard' attribute") is increased from W3 to W1. void로 캐스트하거나 /wd:4834를 컴파일러로 전달하여 경고를 해제할 수 있습니다.You can disable the warning with a cast to void, or by passing /wd:4834 to the compiler

[[nodiscard]] int f() { return 0; }

int main() {
    f(); // warning: discarding return value
         // of function with 'nodiscard'
}

Variadic 템플릿 생성자 기본 클래스 초기화 목록Variadic template constructor base class initialization list

Visual Studio의 이전 버전에서는 템플릿 인수가 누락된 variadic 템플릿 생성자 기본 클래스 초기화 목록이 오류 없이 잘못 허용되었습니다.In previous editions of Visual Studio, a variadic template constructor base class initialization list that was missing template arguments was erroneously allowed without error. Visual Studio 2017 버전 15.7에서는 컴파일러 오류가 발생합니다.In Visual Studio 2017 version 15.7, a compiler error is raised.

Visual Studio 2017 버전 15.7의 다음 코드 예제에서는 오류 C2614: D<int>: 잘못된 멤버 초기화: 'B'는 기본 또는 멤버가 아님이 발생합니다.The following code example in Visual Studio 2017 version 15.7 raises error C2614: D<int>: illegal member initialization: 'B' is not a base or member

template<typename T>
struct B {};

template<typename T>
struct D : B<T>
{

    template<typename ...C>
    D() : B() {} // C2614. Missing template arguments to B.
};

D<int> d;

오류를 수정하려면 B() 식을 B<T>()로 변경하세요.To fix the error, change the B() expression to B<T>().

constexpr 집계 초기화constexpr aggregate initialization

이전 버전의 C++ 컴파일러가 constexpr 집계 초기화를 잘못 처리했습니다. aggregate-init-list에 요소가 너무 많은 잘못된 코드를 허용했으며 잘못된 codegen을 생성했습니다.Previous versions of the C++ compiler incorrectly handled constexpr aggregate initialization; it accepted invalid code in which the aggregate-init-list had too many elements, and produced bad codegen for it. 다음 코드는 이러한 코드의 예제입니다.The following code is an example of such code:

#include <array>
struct X {
    unsigned short a;
    unsigned char b;
};

int main() {
    constexpr std::array<X, 2> xs = {
        { 1, 2 },
        { 3, 4 }
    };
    return 0;
}

Visual Studio 2017 버전 15.7 업데이트 3 이상에서는 이전 예제에서 현재 ‘C2078 이니셜라이저가 너무 많음’이 발생합니다. In Visual Studio 2017 version 15.7 update 3 and later, the previous example now raises C2078 too many initializers. 다음 예제는 코드를 수정하는 방법을 보여 줍니다.The following example shows how to fix the code. 중첩된 brace-init-lists를 사용하여 std::array를 초기화할 때 내부 배열에 자체 braced-list를 제공합니다.When initializing a std::array with nested brace-init-lists, give the inner array a braced-list of its own:

#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의 버그 수정 및 동작 변경Bug fixes and behavior changes in 15.8

Visual Studio 2017 버전 15.8의 모든 컴파일러 변경 사항은 버그 수정 및 동작 변경의 범주에 속하며, 아래에 나열되어 있습니다.The compiler changes in Visual Studio 2017 version 15.8 all fall under the category of bug fixes and behavior changes, and are listed below:

###정규화되지 않은 식별자의 typenametypename on unqualified identifiers

/permissive- 모드에서는 별칭 템플릿 정의의 정규화되지 않은 식별자에 있는 의사 typename 키워드가 컴파일러에서 더 이상 허용되지 않습니다.In /permissive- mode, spurioustypename keywords on unqualified identifiers in alias template definitions are no longer accepted by the compiler. 이제 C7511 'T': 'typename' 키워드 뒤에는 정규화된 이름이 와야 합니다 코드가 생성됩니다.The following code now produces C7511 'T': 'typename' keyword must be followed by a qualified name:

template <typename T>
using  X = typename T;

이 오류를 수정하려면 두 번째 줄을 using X = T;로 변경합니다.To fix the error, change the second line to using X = T;.

별칭 템플릿 정의 오른쪽의 __declspec()__declspec() on right side of alias template definitions

__declspec은 별칭 템플릿 정의의 오른쪽에 더 이상 허용되지 않습니다.__declspec is no longer permitted on the right-hand-side of an alias template definition. 이 코드는 이전에 컴파일러에서 허용되었지만 무시되었으며, 별칭을 사용한 경우에도 사용 중단 경고가 발생하지 않았습니다.This code was previously accepted but ignored by the compiler, and would never result in a deprecation warning when the alias was used.

표준 C++ 특성 [[deprecated]]를 대신 사용할 수 있으며, Visual Studio 2017 버전 15.6에서 적용됩니다.The standard C++ attribute [[deprecated]] may be used instead, and is respected in Visual Studio 2017 version 15.6. 이제 C2760 구문 오류: '__declspec'은 예기치 않은 토큰입니다. 필요한 토큰은 'type specifier'입니다. 코드가 생성됩니다.The following code now produces C2760 syntax error: unexpected token '__declspec', expected 'type specifier':

template <typename T>
using X = __declspec(deprecated("msg")) T;

오류를 수정하려면 코드를 다음으로 변경합니다('=' 별칭 정의 앞에 속성 배치).To fix the error, change to code to the following (with the attribute placed before the '=' of the alias definition):

template <typename T>
using  X [[deprecated("msg")]] = T;

2단계 이름 조회 진단Two-phase name lookup diagnostics

2단계 이름 조회를 위해서는 템플릿 본문에 사용된 종속되지 않은 이름이 정의 시점에 템플릿에 표시될 수 있어야 합니다.Two-phase name lookup requires that non-dependent names used in template bodies must be visible to the template at definition time. 이전에는 Microsoft C++ 컴파일러가 인스턴스화 시점까지 찾을 수 없는 이름을 조회되지 않는 것으로 남겨 두었습니다.Previously, the Microsoft C++ compiler would leave an unfound name as not looked up until instantiation time. 이제, 종속되지 않은 이름을 템플릿 본문에 바인드해야 합니다.Now, it requires that non-dependent names are bound in the template body.

이것을 나타낼 수 있는 한 가지 방법은 종속 기본 클래스를 조회하는 것입니다.One way this can manifest is with lookup into dependent base classes. 이전에는 모든 형식이 확인되는 인스턴스화 시간 동안 이름이 조회되었기 때문에 컴파일러가 종속 기본 클래스에 정의된 이름을 사용할 수 있도록 허용했습니다.Previously, the compiler allowed the use of names that are defined in dependent base classes, because they would be looked up during instantiation time when all the types are resolved. 이제 해당 코드가 오류로 처리됩니다.Now that code is treated as an error. 이러한 경우 기본 클래스 형식으로 한정하거나 this-> 포인터 추가 등으로 종속으로 지정하여 인스턴스화 시점에 변수가 조회되도록 강제 적용할 수 있습니다.In these cases, you can force the variable to be looked up at instantiation time by qualifying it with the base class type or otherwise making it dependent, for example, by adding a this-> pointer.

/permissive- 모드에서는 다음 C3861: 'base_value': 식별자를 찾을 수 없습니다. 코드가 발생합니다.In /permissive- mode, the following code now raises C3861: 'base_value': identifier not found:

template <class T>
struct Base {
    int base_value = 42;
};

template <class T>
struct S : Base<T> {
    int f() {
        return base_value;
    }
};

이 오류를 해결하려면 return 문을 return this->base_value;로 변경합니다.To fix the error, change the return statement to return this->base_value;.

참고: Boost python 라이브러리에는 오랫동안 unwind_type.hpp의 템플릿 정방향 선언에 대한 MSVC 관련 해결 방법이 있었습니다.Note: In the Boost python library, there has been for a long time an MSVC-specific workaround for a template forward declaration in unwind_type.hpp. Visual Studio 2017 버전 15.8(_MSC_VER=1915)부터 /permissive- 모드에서 MSVC 컴파일러가 ADL(인수 종속성 이름 조회)을 올바로 수행하고 다른 컴파일러와 일치하므로 이 해결 방법 보호가 필요 없어졌습니다.Under /permissive- mode starting with Visual Studio 2017 version 15.8 (_MSC_VER=1915), the MSVC compiler does argument-dependent name lookup (ADL) correctly and is consistent with other compilers, making this workaround guard unnecessary. ‘C3861: ‘unwind_type’: 식별자를 찾을 수 없습니다.’ 오류를 방지하려면 Boostorg 리포지토리에서 PR 229를 참조하여 헤더 파일을 업데이트합니다. To avoid error C3861: 'unwind_type': identifier not found, see PR 229 in the Boost repo to update the header file. vcpkg Boost 패키지를 이미 패치했으므로 vcpkg에서 Boost 소스를 가져오거나 업그레이드한 경우 패치를 별도로 적용할 필요가 없습니다.We've already patched the vcpkg Boost package, so if you get or upgrade your Boost sources from vcpkg then you don't need to apply the patch separately.

std 네임스페이스에서 정방향 선언 및 정의forward declarations and definitions in namespace std

C++ 표준에서는 사용자가 std 네임스페이스에 정방향 선언 또는 정의를 추가할 수 없습니다.The C++ standard doesn't allow a user to add forward declarations or definitions into namespace std. std 네임스페이스 또는 std 네임스페이스 내의 네임스페이스에 선언 또는 정의를 추가하면 정의되지 않은 동작이 발생합니다.Adding declarations or definitions to namespace std or to a namespace within namespace std now results in undefined behavior.

향후 Microsoft는 일부 표준 라이브러리 형식이 정의된 위치를 변경할 예정입니다.At some time in the future, Microsoft will move the location where some standard library types are defined. 이 변경으로 인해 std 네임스페이스에 정방향 선언을 추가하는 기존 코드의 호환성이 손상됩니다.This change will break existing code that adds forward declarations to namespace std. 새로운 경고, C4643을 통해 이러한 소스 문제를 파악할 수 있습니다.A new warning, C4643, helps identify such source issues. 이 경고는 /default 모드에서 사용하도록 설정되며 기본적으로 해제되어 있습니다.The warning is enabled in /default mode and is off by default. 이것은 /Wall 또는 /WX로 컴파일되는 프로그램에 영향을 줍니다.It will impact programs that are compiled with /Wall or /WX.

이제 다음 코드는 C4643: C++ 표준에서는 네임스페이스 std에서 'vector' 정방향 선언이 허용되지 않습니다를 생성합니다.The following code now raises C4643: Forward declaring 'vector' in namespace std is not permitted by the C++ Standard.

namespace std {
    template<typename T> class vector;
}

이 오류를 해결하려면 정방향 선언보다는 include 지시문을 사용합니다.To fix the error, use an include directive rather than a forward declaration:

#include <vector>

자신을 위임하는 생성자Constructors that delegate to themselves

C++ 표준에서는 위임하는 생성자가 해당 생성자에 위임하는 경우 컴파일러가 진단을 내보내도록 제안합니다.The C++ standard suggests that a compiler should emit a diagnostic when a delegating constructor delegates to itself. /std:c++17/std:c++latest 모드의 Microsoft C++ 컴파일러는 이제 C7535: 'X::X': 위임하는 생성자는 자신을 호출합니다를 생성합니다.The Microsoft C++ compiler in /std:c++17 and /std:c++latest modes now raises C7535: 'X::X': delegating constructor calls itself.

이 오류가 없으면 다음 프로그램이 컴파일되지만 무한 루프가 생성됩니다.Without this error, the following program will compile but will generate an infinite loop:

class X {
public:
    X(int, int);
    X(int v) : X(v){}
};

무한 루프를 방지하려면 다른 생성자에 위임합니다.To avoid the infinite loop, delegate to a different constructor:

class X {
public:

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

상수 식을 사용한 offsetofoffsetof with constant expressions

지금까지 offsetofreinterpret_cast가 필요한 매크로를 사용하여 구현되었습니다.offsetof has traditionally been implemented using a macro that requires a reinterpret_cast. 이 사용법은 상수 식을 필요로 하는 컨텍스트에서 올바르지 않지만, Microsoft C++ 컴파일러에서는 일반적으로 허용되었습니다.This usage is illegal in contexts that require a constant expression, but the Microsoft C++ compiler has traditionally allowed it. 표준 라이브러리의 일부로 제공되는 offsetof 매크로는 컴파일러 내장 함수( __builtin_offsetof)를 올바르게 사용하지만, 매크로 트릭을 사용하여 고유한 offsetof를 정의하는 사람이 많았습니다.The offsetof macro that is shipped as part of the standard library correctly uses a compiler intrinsic (__builtin_offsetof), but many people have used the macro trick to define their own offsetof.

Visual Studio 2017 버전 15.8에서 컴파일러는 reinterpret_cast 연산자가 기본 모드로 표시될 수 있는 영역을 제한하여 코드가 표준 C++ 동작을 준수하도록 합니다.In Visual Studio 2017 version 15.8, the compiler constrains the areas that these reinterpret_cast operators can appear in the default mode, to help code conform to standard C++ behavior. /permissive- 아래에서는 제약 조건이 더욱 엄격합니다.Under /permissive-, the constraints are even stricter. 상수 식이 필요한 위치에 offsetof의 결과를 사용하면 C4644 ‘상수 식에 매크로 기반 offsetof 패턴을 사용하는 것은 표준이 아닙니다. 대신 C++ 표준 라이브러리에 정의된 offsetof를 사용하세요.’ 또는 C2975 ‘템플릿 인수가 잘못되었습니다. 컴파일 시간 상수 식이 필요합니다.’라는 경고를 실행하는 코드가 생성될 수 있습니다. Using the result of an offsetof in places that require constant expressions may result in code that issues warning 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/std:c++17 모드에서는 C4644가, /permissive- 모드에서는 C2975 코드가 발생합니다.The following code raises C4644 in /default and /std:c++17 modes, and C2975 in /permissive- mode:

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;
    default: return 1;
    }
}

이 오류를 해결하려면 <cstddef>를 통해 정의된 대로 offsetof를 사용합니다.To fix the error, use offsetof as defined via <cstddef>:

#include <cstddef>

struct Data {
    int x;
};

int main()
{
    switch (0) {
    case offsetof(Data, x): return 0;
    default: return 1;
    }
}

팩 확장의 대상이 되는 기본 클래스의 CV 한정자cv-qualifiers on base classes subject to pack expansion

이전 버전의 Microsoft C++ 컴파일러는 기본 클래스에 팩 확장도 적용되는 경우 기본 클래스에 cv 한정자가 있음을 검색하지 못했습니다.Previous versions of the Microsoft C++ compiler didn't detect that a base-class had cv-qualifiers if it was also subject to pack expansion.

Visual Studio 2017 버전 15.8의 /permissive- 모드에서는 C3770 'const S': 유효한 기본 클래스가 아닙니다. 코드가 발생합니다.In Visual Studio 2017 version 15.8, in /permissive- mode the following code raises C3770 'const S': is not a valid base class:

template<typename... T>
class X : public T... { };

class S { };

int main()
{
    X<const S> x;
}

template 키워드 및 중첩된 이름 지정자template keyword and nested-name-specifiers

/permissive- 모드의 컴파일러에서 이제 종속된 중첩 이름 지정자 뒤에 오는 템플릿 이름을 template 키워드로 시작해야 합니다.In /permissive- mode, the compiler now requires the template keyword to precede a template-name when it comes after a dependent nested-name-specifier.

/permissive- 모드의 다음 코드에서 이제 C7510: ‘’example’: 종속 템플릿 이름을 사용하는 경우 ‘template’로 시작해야 합니다. 참고: 컴파일되는 클래스 템플릿 인스턴스화 ‘X’에 대한 참조를 확인하세요. The following code in /permissive- mode now raises C7510: 'example': use of dependent template name must be prefixed with 'template'. note: see reference to class template instantiation 'X' being compiled:

template<typename T> struct Base
{
    template<class U> void example() {}
};

template<typename T>
struct X : Base<T>
{
    void example()
    {
        Base<T>::example<int>();
    }
};

이 오류를 해결하려면 다음 예제에서 표시된 대로 template 키워드를 Base<T>::example<int>(); 문에 추가합니다.To fix the error, add the template keyword to the Base<T>::example<int>(); statement, as shown in the following example:

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의 버그 수정 및 동작 변경Bug fixes and behavior changes in 15.9

멤버 별칭 템플릿의 식별자Identifiers in member alias templates

멤버 별칭 템플릿 정의에서 사용된 식별자를 사용하기 전에 선언해야 합니다.An identifier used in a member alias template definition must be declared before use.

이전 버전의 컴파일러에서 다음 코드가 허용되었습니다.In previous versions of the compiler, the following code was allowed:

template <typename... Ts>
struct A
{
  public:
    template <typename U>
    using from_template_t = decltype(from_template(A<U>{}));

  private:
    template <template <typename...> typename Type, typename... Args>
    static constexpr A<Args...> from_template(A<Type<Args...>>);
};

A<>::from_template_t<A<int>> a;

Visual Studio 2017 버전 15.9의 /permissive- 모드에서 컴파일러는 C3861: 'from_template': 식별자를 찾을 수 없음을 발생시킵니다.In Visual Studio 2017 version 15.9, in /permissive- mode, the compiler raises C3861: 'from_template': identifier not found.

오류를 해결하려면 from_template_t 전에 from_template를 선언합니다.To fix the error, declare from_template before from_template_t.

모듈 변경Modules changes

Visual Studio 2017 버전 15.9에서 컴파일러는 모듈의 명령줄 옵션이 모듈 생성 쪽과 모듈 사용 쪽에서 일치하지 않을 때마다 C5050을 발생시킵니다.In Visual Studio 2017, version 15.9, the compiler raises C5050 whenever the command-line options for modules aren't consistent between the module creation and module consumption sides. 다음 예제에서는 두 가지 문제가 있습니다.In the following example, there are two issues:

  • 사용 쪽(main.cpp)에서 /EHsc 옵션을 지정하지 않았습니다.On the consumption side (main.cpp), the option /EHsc isn't specified.

  • C++ 버전이 생성 쪽에서는 /std:c++17이고, 사용 쪽에서는 /std:c++14입니다.The C++ version is /std:c++17 on the creation side, and /std:c++14 on the consumption side.

cl /EHsc /std:c++17 m.ixx /experimental:module
cl /experimental:module /module:reference m.ifc main.cpp /std:c++14

컴파일러는 다음 두 경우 모두에 대해 C5050을 생성합니다. 경고 C5050: 'm' 모듈을 가져오는 동안 호환되지 않는 환경: C++ 버전이 일치하지 않습니다. 현재 "201402" 모듈 버전 "201703"The compiler raises C5050 for both of these cases: warning C5050: Possible incompatible environment while importing module 'm': mismatched C++ versions. Current "201402" module version "201703".

또한 컴파일러는 .ifc 파일이 변조될 때마다 C7536을 발생시킵니다.The compiler also raises C7536 whenever the .ifc file has been tampered with. 모듈 인터페이스의 헤더에는 아래 내용의 SHA2 해시가 포함됩니다.The header of the module interface contains an SHA2 hash of the contents below it. 가져올 때 .ifc 파일을 동일한 방식으로 해시한 다음, 헤더에 제공된 해시와 비교합니다.On import, the .ifc file is hashed in the same way and then checked against the hash provided in the header. 해시가 일치하지 않으면 오류 C7536이 발생합니다. ifc에서 무결성 검사에 실패했습니다. 예상된 SHA2: '66d5c8154df0c71d4cab7665bab4a125c7ce5cb9a401a4d8b461b706ddd771c6' .If these don't match, error C7536 is raised: ifc failed integrity checks. Expected SHA2: '66d5c8154df0c71d4cab7665bab4a125c7ce5cb9a401a4d8b461b706ddd771c6'.

별칭 및 추론되지 않은 컨텍스트와 관련된 부분 순서Partial ordering involving aliases and non-deduced contexts

추론되지 않은 컨텍스트에서 별칭을 포함하는 부분 순서 지정 규칙의 구현에 차이가 있습니다.Implementations diverge in the partial ordering rules involving aliases in non-deduced contexts. 다음 예제에서 Clang이 코드를 허용하는 반면 /permissive- 모드의 GCC 및 Microsoft C++ 컴파일러는 오류를 발생시킵니다.In the following example, GCC and the Microsoft C++ compiler (in /permissive- mode) raise an error, while Clang accepts the code.

#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;
}

이전 예제는 C2668을 발생시킵니다.The previous example raises C2668:

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>)'

구현 차이는 C++ 표준의 표현 회귀로 인한 것입니다.The implementation divergence is because of a regression in the C++ standard wording. 핵심 문제 2235가 해결되면서 이러한 오버로드의 순서를 지정할 수 있는 일부 텍스트가 제거되었습니다.The resolution to core issue 2235 removed some text that would allow these overloads to be ordered. 현재 C++ 표준은 이러한 함수의 순서를 부분적으로 지정하는 메커니즘을 제공하지 않으므로 함수가 모호하다고 여겨집니다.The current C++ standard doesn't provide a mechanism to partially order these functions, so they're considered ambiguous.

임시 해결책으로, 이 문제를 해결하는 데 부분 순서 지정을 사용하지 않고As a workaround, we recommended that you not rely on partial ordering to resolve this problem. SFINAE를 사용하여 특정 오버로드를 제거하는 것이 좋습니다.Instead, use SFINAE to remove particular overloads. 다음 예제에서 AllocA의 특수화인 경우 IsA 도우미 클래스를 사용하여 첫 번째 오버로드를 제거합니다.In the following example, we use a helper class IsA to remove the first overload when Alloc is a specialization of A:

#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;
}

템플릿 지정된 함수 정의의 잘못된 식 및 비 리터럴 형식Illegal expressions and non-literal types in templated function definitions

잘못된 식 및 비 리터럴 형식은 이제 명시적으로 특수화된 템플릿 지정된 함수의 정의에서 바르게 진단됩니다.Illegal expressions and non-literal types are now correctly diagnosed in the definitions of templated functions that are explicitly specialized. 이전에는 함수 정의에 대해 이러한 오류를 내보내지 않았습니다.Previously, such errors weren't emitted for the function definition. 그러나 잘못된 식 또는 비 리터럴 형식은 상수 식의 일부로 평가되는 경우에 진단됩니다.However, the illegal expression or non-literal type would still have been diagnosed if evaluated as part of a constant expression.

이전 버전의 Visual Studio에서 다음 코드는 경고 없이 컴파일됩니다.In previous versions of Visual Studio, the following code compiles without warning:

void g();

template<typename T>
struct S
{
    constexpr void f();
};

template<>
constexpr void S<int>::f()
{
    g(); // C3615 in 15.9
}

Visual Studio 2017 버전 15.9에서 다음 코드를 실행하면 이 오류가 발생합니다.In Visual Studio 2017 version 15.9, the code raises this error:

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'.

이 오류를 방지하려면 f() 함수의 명시적 인스턴스화에서 constexpr 한정자를 제거합니다.To avoid the error, remove the constexpr qualifier from the explicit instantiation of the function f().

Visual Studio 2015의 C++ 규칙 향상C++ conformance improvements in Visual Studio 2015

Visual Studio 2015, 업데이트 3까지 규칙 향상의 전체 목록은 Visual C++ What's New 2003 through 2015(2003부터 2015까지 Visual C++의 새로운 기능)를 참조하세요.For the complete list of conformance improvements up through Visual Studio 2015 Update 3, see Visual C++ What's New 2003 through 2015.

참고 항목See also

Microsoft C++ 언어 규칙 테이블Microsoft C++ language conformance table