Visual Studio 2022의 C++ 규칙 향상, 동작 변경 및 버그 수정

Visual Studio의 Microsoft C/C++(MSVC)는 모든 릴리스에서 규칙을 개선하고 버그를 수정합니다. 이 문서에서는 주 릴리스 및 버전별 주요 개선 사항을 나열합니다. 특정 버전의 변경 내용으로 직접 이동하려면 이 문서 내 링크를 사용합니다.

이 문서에는 Visual Studio 2022의 변경 내용이 나와 있습니다.

Visual Studio 2019의 변경 내용은 Visual Studio 2019의 C++ 규칙 향상을 참조하세요.
Visual Studio 2017의 변경 내용은 Visual Studio 2017의 C++ 규칙 향상을 참조하세요.
이전 버전의 변경 내용은 Visual C++ 새로운 기능 2003부터 2015까지를 참조하세요.

Visual Studio 2022 버전 17.9의 규칙 향상

Visual Studio 2022 버전 17.9에는 Microsoft C/C++ 컴파일러의 다음과 같은 규칙 향상, 버그 수정 및 동작 변경 내용이 포함되어 있습니다.

표준 템플릿 라이브러리의 변경 내용에 대한 자세한 요약은 STL Changelog VS 2022 17.9를 참조하세요.

C의 _Alignas 구조적 형식에 적용

Visual Studio 2022 버전 17.9 이전의 Visual C++ 버전에서는 선언의 구조체 형식 옆에 표시될 때 _Alignas ISO-C 표준에 따라 올바르게 적용되지 않았습니다. 예시:

// compile with /std:c17
#include <stddef.h>
struct Outer
{
    _Alignas(32) struct Inner { int i; } member1;
    struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");

ISO-C 표준에 따르면 이 코드는 진단을 내보내지 않고 static_assert 컴파일해야 합니다. 지시문은 _Alignas 멤버 변수 member1에만 적용됩니다. 의 맞춤 struct Inner을 변경해서는 안 됩니다. 그러나 Visual Studio의 릴리스 17.9.1 이전에는 진단 "잘못된 맞춤"이 내보내졌습니다. 내의 32 바이트 오프셋struct Outer에 맞춰진 member2 컴파일러입니다.

이 문제를 해결하는 것은 이진 호환성이 손상되는 변경이므로 이 동작 변경이 적용되면 경고가 내보내집니다. 위의 코드인 경고 C5274의 경우 이제 경고 수준 1에서 "_Alignas 'Inner' 형식에 더 이상 적용되지 않습니다(선언된 데이터 개체에만 적용됨)" 가 내보내집니다.

이전 버전의 Visual Studio _Alignas 에서는 익명 형식 선언 옆에 표시되었을 때 무시되었습니다. 예시:

// compile with /std:c17
#include <stddef.h>
struct S {
    _Alignas(32) struct { int anon_member; };
    int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");

이전에는 이 코드를 컴파일할 때 두 명령문이 모두 static_assert 실패했습니다. 이제 코드가 컴파일되지만 다음 수준 1 경고가 표시됩니다.

warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)

이전 동작 _Alignas(N)__declspec(align(N))을 원하는 경우 . 와 달리 _Alignas형식 declspec(align) 에 적용할 수 있습니다.

__VA_OPT__ 에서 확장으로 사용할 수 있습니다. /Zc:preprocessor

__VA_OPT__ 가 C++20 및 C23에 추가되었습니다. 그 이전에, variadic 매크로에서 쉼표를 유도하는 표준 방법이 없었다. 이전 버전과의 호환성을 __VA_OPT__ 향상하기 위해 모든 언어 버전에서 토큰 기반 전처리기 /Zc:preprocessor 에서 사용하도록 설정됩니다.

예를 들어 이제 오류 없이 컴파일됩니다.

#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))

// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")

C23 언어

C23의 경우 컴파일러 스위치를 사용할 때 다음을 /std:clatest 사용할 수 있습니다.

typeof
typeof_unqual

다음은 모든 C 언어 버전에서 사용할 수 있습니다.

__typeof__
__typeof_unqual__

C++ 표준 라이브러리

C++23 기능

Visual Studio 2022 버전 17.8의 규칙 향상

Visual Studio 2022 버전 17.8에는 Microsoft C/C++ 컴파일러에서 다음과 같은 규칙 향상, 버그 수정 및 동작 변경 내용이 포함되어 있습니다.

/FU 오류 발생

C 컴파일러는 일정 시간 동안 관리되는 컴파일을 지원하지 않더라도 이 옵션을 수락 /FU 하는 데 사용됩니다. 이제 오류가 발생합니다. 이 옵션을 전달하는 프로젝트는 C++/CLI 프로젝트로만 제한해야 합니다.

C++ 표준 라이브러리

C++23 명명된 모듈 stdstd.compat 이제 .로 컴파일할 /std:c++20때 사용할 수 있습니다.

C++ 표준 라이브러리의 변경 내용에 대한 자세한 요약은 STL Changelog VS 2022 17.8을 참조하세요.

Visual Studio 2022 버전 17.7의 규칙 향상

Visual Studio 2022 버전 17.7에는 Microsoft C/C++ 컴파일러에서 강조 표시된 다음과 같은 규칙 향상, 버그 수정 및 동작 변경 내용이 포함되어 있습니다.

C 컴파일러에 추가됨 /std:clatest

이 스위치는 C++ 컴파일러의 스위치처럼 /std:c++latest 동작합니다. 이 스위치를 사용하면 현재 구현된 모든 컴파일러와 다음 초안 C 표준에 대해 제안된 표준 라이브러리 기능뿐만 아니라 진행 중인 일부 및 실험적 기능을 사용할 수 있습니다.

C++ 표준 라이브러리

<print> 이제 라이브러리가 지원됩니다. P2093R14 형식 출력을 참조하세요.

구현되었습니다 views::cartesian_product.

표준 템플릿 라이브러리의 변경 내용에 대한 자세한 요약은 STL Changelog VS 2022 17.7을 참조하세요.

using 규칙

이전에는 이 지시문으로 using 인해 사용된 네임스페이스의 이름이 다시 표시되지 않을 때 기본 표시될 수 있었습니다. 이로 인해 활성 지시문이 없는 using 경우에도 정규화되지 않은 이름 조회가 네임스페이스에서 이름을 찾을 수 있습니다.

다음은 새 동작과 이전 동작의 몇 가지 예입니다.
"(1)"에 대한 다음 주석의 참조는 네임스페이스에서 A호출을 f<K>(t) 의미합니다.

namespace A
{ 
    template<typename K, typename T> 
    auto f2(T t)
    { 
        return f<K>(t); // (1) Unqualified lookup should not find anything
    } 
} 

namespace B
{ 
    template<typename K, typename T> 
    auto f(T t) noexcept
    { // Previous behavior: This function was erroneously found during unqualified lookup at (1)
        return A::f2<K>(t); 
    } 
} 

namespace C
{ 
    template<typename T> 
    struct S {}; 

    template<typename, typename U> 
    U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function 
} 

namespace D
{ 
    using namespace B; 

    void h()
    { 
        D::f<void>(C::S<int>()); 
    } 
} 

동일한 기본 문제로 인해 이전에 컴파일된 코드가 이제 거부될 수 있습니다.

#include <memory>
namespace Addin {}
namespace Gui
{
    using namespace Addin;
}

namespace Addin
{
    using namespace std;
}

// This previously compiled, but now emits error C2065 for undeclared name 'allocator'.
// This should be declared as 'std::allocator<T*>' because the using directive nominating
// 'std' is not active at this point.
template <class T, class U = allocator<T*>>
class resource_list
{
};

namespace Gui
{
    typedef resource_list<int> intlist;
}

Visual Studio 2022 버전 17.6의 규칙 향상

Visual Studio 2022 버전 17.6에는 Microsoft C/C++ 컴파일러에서 다음과 같은 규칙 향상, 버그 수정 및 동작 변경 내용이 포함되어 있습니다.

복합 volatile 할당은 더 이상 사용되지 않습니다.

C++20은 한정 volatile된 형식에 특정 연산자를 적용하는 것이 더 이상 사용되지 않습니다. 예를 들어 다음 코드가 다음과 같이 cl /std:c++20 /Wall test.cpp컴파일되는 경우

void f(volatile int& expr)
{
   ++expr;
}

컴파일러에서 생성합니다.test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20

C++20에서는 복합 할당 연산자(양식 @=의 연산자)가 더 이상 사용되지 않습니다. C++23에서는 C++20에서 제외된 복합 연산자가 더 이상 사용되지 않습니다. 예를 들어 C++23에서 다음 코드는 경고를 생성하지 않지만 C++20에서는 경고를 생성합니다.

void f(volatile int& e1, int e2)
{
   e1 += e2;
}

이 변경에 대한 자세한 내용은 CWG:2654를 참조 하세요.

식에서 같음을 다시 쓰는 것은 호환성이 손상되는 변경(P2468R2)이 적습니다.

C++20 에서 P2468R2 다음과 같은 코드를 수락하도록 컴파일러를 변경했습니다.

struct S
{
    bool operator==(const S&);
    bool operator!=(const S&);
};
bool b = S{} != S{};

컴파일러는 이 코드를 허용합니다. 즉, 컴파일러가 다음과 같은 코드를 사용하는 것이 더 엄격합니다.

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

bool b = S{} == S{};

컴파일러 버전 17.5는 이 프로그램을 허용합니다. 컴파일러의 버전 17.6은 이를 거부합니다. 이 문제를 해결하려면 모호성을 제거하도록 operator== 추가 const 합니다. 또는 다음 예제와 같이 정의에 해당하는 operator!= 항목을 추가합니다.

struct S
{
  operator bool() const;
  bool operator==(const S&);
  bool operator!=(const S&);
};

bool b = S{} == S{};

Microsoft C/C++ 컴파일러 버전 17.5 및 17.6은 이전 프로그램과 두 버전의 호출 S::operator== 을 모두 수락합니다.

P2468R2 설명된 일반적인 프로그래밍 모델은 형식에 해당하는 operator!= 경우 일반적으로 다시 쓰기 동작을 표시하지 않는다는 것입니다. 해당 operator!= 항목을 추가하는 것은 이전에 C++17에서 컴파일된 코드에 대해 제안된 수정 사항입니다. 자세한 내용은 프로그래밍 모델을 참조하세요.

Visual Studio 2022 버전 17.4의 규칙 개선

Visual Studio 2022 버전 17.4에는 다음과 같은 Microsoft C/C++ 컴파일러의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.

고정 형식이 없는 범위가 지정되지 않은 enum의 기본 형식

Visual Studio 2022 버전 17.4 이전 버전의 Visual Studio에서 C++ 컴파일러는 고정된 기본 형식이 없는 범위가 지정되지 않은 열거형의 기본 형식을 정확하게 결정하지 못했습니다. /Zc:enumTypes에서 이제 표준 동작을 올바르게 구현합니다.

C++ 표준에서는 enum의 기본 형식이 해당 enum의 모든 열거자를 저장할 수 있을 만큼 충분히 커야 합니다. 충분히 큰 열거자는 enum의 기본 형식을 unsigned int, long long 또는 unsigned long long로 설정할 수 있습니다. 이전에는 이러한 enum 형식이 항상 열거자 값에 관계없이 Microsoft 컴파일러의 기본 형식 int를 가졌습니다.

사용하도록 설정하면 /Zc:enumTypes 옵션은 잠재적인 원본 및 이진 호환성이 손상되는 변경입니다. 수정 사항이 이진 호환성에 영향을 줄 수 있으므로 기본적으로 꺼져 있고 사용하도록 설정 /permissive-되지 않습니다. 일부 열거형 형식은 규칙 수정을 사용하도록 설정하면 크기가 변경됩니다. 특정 Windows SDK 헤더에는 이러한 열거형 정의가 포함됩니다.

예제

enum Unsigned
{
    A = 0xFFFFFFFF // Value 'A' does not fit in 'int'.
};

// Previously, failed this static_assert. Now passes with /Zc:enumTypes.
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);

template <typename T>
void f(T x)
{
}

int main()
{
    // Previously called f<int>, now calls f<unsigned int>.
    f(+A);
}

// Previously this enum would have an underlying type of `int`, but Standard C++ requires this to have
// a 64-bit underlying type. Using /Zc:enumTypes changes the size of this enum from 4 to 8, which could
// impact binary compatibility with code compiled with an earlier compiler version or without the switch.
enum Changed
{
    X = -1,
    Y = 0xFFFFFFFF
};

고정된 기본 형식이 없는 enum 정의 내의 열거자 형식

Visual Studio 2022 버전 17.4 이전 버전의 Visual Studio에서는 C++ 컴파일러가 열거자 유형을 올바르게 모델링하지 않았습니다. 열거형의 닫는 중괄호 앞에 고정된 기본 형식이 없는 열거형에서 잘못된 형식을 가정할 수 있습니다. /Zc:enumTypes에서 컴파일러는 이제 표준 동작을 올바르게 구현합니다.

C++ 표준은 고정된 기본 형식이 없는 열거형 정의 내에서 이니셜라이저가 열거자의 형식을 결정하도록 지정합니다. 또는 이니셜라이저가 없는 열거자의 경우 이전 열거자의 형식으로 지정합니다(오버플로를 고려). 이전에는 이러한 열거자에 항상 기본 형식(일반적으로 int)에 대한 자리 표시자와 함께 추론된 열거형 형식이 주어졌습니다.

사용하도록 설정하면 /Zc:enumTypes 옵션은 잠재적인 원본 및 이진 호환성이 손상되는 변경입니다. 수정 사항이 이진 호환성에 영향을 줄 수 있으므로 기본적으로 꺼져 있고 사용하도록 설정 /permissive-되지 않습니다. 일부 열거형 형식은 규칙 수정을 사용하도록 설정하면 크기가 변경됩니다. 특정 Windows SDK 헤더에는 이러한 열거형 정의가 포함됩니다.

예시

enum Enum {
    A = 'A',
    B = sizeof(A)
};

static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes

이 예제에서 열거자는 A 열거형의 닫는 중괄호 앞에 형식 char 이 있어야 하므로 Bsizeof(char). /Zc:enumTypes 수정 전에는 A가 추론된 기본 형식 int인 열거형 형식 Enum을 사용했으며, Bsizeof(Enum) 또는 4를 사용하여 초기화되었습니다.

Visual Studio 2022 버전 17.3의 규칙 개선

Microsoft Visual StudioVisual Studio 2022 버전 17.3에는 다음과 같은 Microsoft C/C++ 컴파일러의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.

C: 포인터 간의 한정자 호환성 검사 개선

C 컴파일러가 포인터 간 한정자 특히 void*를 제대로 비교하지 못했습니다. 이 결함으로 인해 const int**void* 간의 비호환성 및 int* volatile*void* 간의 호환성이 잘못 진단될 수 있습니다.

예제

void fn(void* pv) { (pv); }

int main()
{
    int t = 42;
    int* pt = &t;
    int* volatile * i = &pt;
    fn(i);    // Now raises C4090
    const int** j = &pt;
    fn(j);    // No longer raises C4090
}

Visual Studio 2022 버전 17.2의 규칙 개선

Visual Studio 2022 버전 17.2에는 다음과 같은 Microsoft C/C++ 컴파일러의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.

종결되지 않은 양방향 문자 경고

Visual Studio 2022 버전 17.2에는 주석 및 문자열에서 종결되지 않은 유니코드 양방향 문자에 대해 수준 3 경고 C5255가 추가됩니다. 이 경고는 Nicholas Boucher 및 Ross Anderson의 Trojan Source: Invisible Vulnerabilities에 설명된 보안 문제를 해결합니다. 유니코드 양방향 문자에 대한 자세한 내용은 Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM을 참조하세요.

경고 C5255는 변환 후 유니코드 양방향 문자를 포함하는 파일만 해결합니다. 이 경고는 UTF-8, UTF-16 및 UTF-32 파일에 적용되므로 적절한 소스 인코딩을 제공해야 합니다. 이는 원본 호환성이 손상되는 변경입니다.

예제(이전/이후)

Visual Studio 2022 버전 17.2 이전의 Visual Studio 버전에서는 종결되지 않은 양방향 문자가 경고를 생성하지 않았습니다. Visual Studio 2022 버전 17.2는 C5255 경고를 생성합니다.

// bidi.cpp
int main() {
    const char *access_level = "user";
    // The following source line contains bidirectional Unicode characters equivalent to:
    //    if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
    // In most editors, it's rendered as:
    //    if ( strcmp(access_level, "user") ) { // Check if admin
    if ( strcmp(access_level, "user‮ ⁦// Check if admin ⁩ ⁦") ) {
        printf("You are an admin.\n");
    }
    return 0;
}

/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/

from_chars()float 타이브레이커

Visual Studio 2022 버전 17.2에서 <charconv>from_chars()float 타이브레이커 규칙에서 잘못된 결과를 생성한 버그가 수정되었습니다. 이 버그는 좁은 범위 내에서 연속한 float 값의 정확히 중간점에 있던 10진수 문자열에 영향을 주었습니다. (영향을 받는 값이 가장 작고 가장 큰 값은 각각 및 131071.98828125가장 큰 값입니다32768.009765625.) tiebreaker 규칙은 "짝수"로 반올림하려고 했고 "짝수"는 "down"로 진행되었지만 구현이 "up"(double영향을 받지 않음)으로 잘못 반올림되었습니다. 자세한 내용 및 구현 세부 정보는 microsoft/STL#2366을 참조하세요.

이 변경은 지정된 사례 범위의 런타임 동작에 영향을 줍니다.

예시

// from_chars_float.cpp
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
    const double dbl  = 32768.009765625;
    const auto sv     = "32768.009765625"sv;
    float flt         = 0.0f;
    const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
    assert(result.ec == errc{});
    printf("from_chars() returned: %.1000g\n", flt);
    printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}

Visual Studio 2022 버전 17.2 이전:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.01171875
This rounded UP.

Visual Studio 2022 버전 17.2 이상:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.0078125
This rounded DOWN.

/Zc:__STDC__는 C에 __STDC__를 제공합니다.

C 표준에서는 준수 C 구현이 __STDC__1로 정의해야 합니다. __STDC__1일 때 POSIX 함수를 노출하지 않는 UCRT의 동작으로 인해, 안정적인 언어 버전에 호환성이 손상되는 변경을 도입하지 않고는 기본적으로 C에 대해 이 매크로를 정의할 수 없습니다. Visual Studio 2022 버전 17.2 이상에서는 이 매크로를 정의하는 규칙 옵션 /Zc:__STDC__가 추가되었습니다. 음수 버전의 옵션은 없습니다. 현재 C의 이후 버전에 기본적으로 이 옵션을 사용할 계획을 세우고 있습니다.

이는 원본 호환성이 손상되는 변경입니다. /Zc:__STDC__와 함께 C11 모드 C17이 활성화된 경우(/std:c11 또는 /std:c17)에 적용됩니다.

예제

// test__STDC__.c
#include <io.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
#if __STDC__
    int f = _open("file.txt", _O_RDONLY);
    _close(f);
#else
    int f = open("file.txt", O_RDONLY);
    close(f);
#endif
}

/* Command line behavior

C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__

*/

누락된 중괄호에 대한 경고

C5246 경고는 하위 개체의 집계 초기화 중에 누락된 중괄호를 보고합니다. Visual Studio 2022 버전 17.2 이전에서는 경고가 익명 struct 또는 union의 사례를 처리하지 못했습니다.

이는 원본 호환성이 손상되는 변경입니다. 기본적으로 해제된 C5246 경고를 사용하도록 설정하면 적용됩니다.

예제

Visual Studio 2022 버전 17.2 이상에서 이 코드는 이제 오류를 발생시킵니다.

struct S {
   union {
      float f[4];
      double d[2];
   };
};

void f()
{
   S s = { 1.0f, 2.0f, 3.14f, 4.0f };
}

/* Command line behavior
cl /Wall /c t.cpp

t.cpp(10): warning C5246: 'anonymous struct or union': the initialization of a subobject should be wrapped in braces
*/

이 문제를 해결하려면 이니셜라이저에 중괄호를 추가하세요.

void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}

Visual Studio 2022 버전 17.1의 규칙 개선

Visual Studio 2022 버전 17.1에는 다음과 같은 Microsoft C/C++ 컴파일러의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.

비로컬 람다 식에서 잘못된 형식의 캡처 기본값 검색

C++ 표준은 블록 범위의 람다 식에 캡처 기본값만 허용합니다. Visual Studio 2022 버전 17.1 이상에서 컴파일러는 비로컬 람다 식에서 캡처 기본값이 허용되지 않는 경우를 감지합니다. 새 수준 4 경고인 C5253을 생성합니다.

이는 원본 호환성이 손상되는 변경입니다. 해당 변경 사항은 새로운 람다 프로세서를 사용하는 모든 모드, 즉 /Zc:lambda, /std:c++20 또는 /std:c++latest에 적용됩니다.

예제

Visual Studio 2022 버전 17.1에서 이제 이 코드는 오류를 내보냅니다.

#pragma warning(error:5253)

auto incr = [=](int value) { return value + 1; };

// capture_default.cpp(3,14): error C5253: a nonlocal lambda cannot have a capture default
// auto incr = [=](int value) { return value + 1; };
//              ^

이 문제를 해결하려면 다음 캡처 기본값을 제거합니다.

#pragma warning(error:5253)

auto incr = [](int value) { return value + 1; };

C4028은 이제 함수 포인터 작업에 대한 C4133임

Visual Studio 2022 버전 17.1 이전에는 컴파일러가 C 코드의 특정 포인터 함수 비교에서 잘못된 오류 메시지를 보고했습니다. 이 잘못된 메시지는 인수 개수가 같지만 유형이 호환되지 않는 두 함수 포인터를 비교했을 때 보고되었습니다. 이제 함수 매개 변수 불일치가 아닌, 포인터 함수 비호환성이 있음을 알리는 다른 경고를 표시합니다.

이는 원본 호환성이 손상되는 변경입니다. 해당 변경 사항은 코드가 C로 컴파일될 때 적용됩니다.

예시

int f1(int); 
int f2(char*); 
int main(void) 
{ 
    return (f1 == f2); 
}
// Old warning:
// C4028: formal parameter 1 different from declaration
// New warning:
// C4113: 'int (__cdecl *)(char *)' differs in parameter lists from 'int (__cdecl *)(int)'

비 의존적 오류 static_assert

Visual Studio 2022 버전 17.1 이상에서 연결된 static_assert 식이 종속 식이 아닌 경우 컴파일러는 구문 분석 시 식을 평가합니다. 식이 false로 계산되는 경우 컴파일러에서 오류를 내보냅니다. 이전에는 static_assert가 함수 템플릿 본문 또는 클래스 템플릿 본문 내에 있을 경우 컴파일러에서 이러한 분석을 실시하지 않았습니다.

이는 원본 호환성이 손상되는 변경입니다. 해당 변경 사항은 /permissive- 또는 /Zc:static_assert를 의미하는 모든 모드에 적용됩니다. 이 동작 변경 사항은 /Zc:static_assert- 컴파일러 옵션을 통해 사용하지 않도록 설정할 수 있습니다.

예제

Visual Studio 2022 버전 17.1 이상에서 이 코드는 이제 오류를 발생시킵니다.

template<typename T>
void f()
{
   static_assert(false, "BOOM!");
}

이 문제를 해결하려면 식을 종속으로 만듭니다. 예를 들면 다음과 같습니다.

template<typename>
constexpr bool dependent_false = false;

template<typename T>
void f()
{
   static_assert(dependent_false<T>, "BOOM!");
}

이 변경 사항으로 컴파일러는 함수 템플릿 f가 인스턴스화되었을 경우에만 오류를 내보냅니다.

Visual Studio 2022 버전 17.0의 규칙 향상

Visual Studio 2022 버전 17.0에는 다음과 같은 Microsoft C/C++ 컴파일러의 규칙 향상, 버그 수정 및 동작 변경이 포함되어 있습니다.

열거형 형식의 비트 필드 너비에 대한 경고

열거형 형식의 인스턴스를 비트 필드로 선언하는 경우 비트 필드의 너비는 열거형의 가능한 모든 값을 수용해야 합니다. 그렇지 않으면 컴파일러가 진단 메시지를 표시합니다. 다음 예제를 고려해보세요.

enum class E : unsigned { Zero, One, Two };

struct S {
  E e : 1;
};

한 프로그래머가 클래스 멤버 S::e에 명시적으로 명명된 enum 값이 있다고 예상할 수 있습니다. 열거형 요소의 수를 고려할 때 이는 불가능합니다. 비트 필드는 E(개념적으로 E의 ‘도메인’)의 명시적으로 제공된 값 범위를 포함할 수 없습니다. 비트 필드 너비가 열거형의 도메인에 대해 충분히 크지 않다는 문제를 해결하기 위해 새 경고(기본적으로 해제)가 MSVC에 추가됩니다.

t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
  E e : 1;
    ^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
                                     ^

이 컴파일러 동작은 모든 /std/permissive 모드에 영향을 미치는 소스 및 호환성이 손상되는 이진 변경입니다.

nullptr 또는 0에 대해 정렬된 포인터 비교 시 오류 발생

C++ Standard에서는 nullptr 또는 0에 대해 정렬된 포인터 비교를 실수로 허용했습니다. 예를 들면 다음과 같습니다.

bool f(int *p)
{
   return p >= 0;
}

WG21 문서 N3478에서는 이러한 실수가 제거되었습니다. 이 변경 내용은 MSVC에서 구현됩니다. 예제를 /permissive- (및 /diagnostics:caret )를 사용하여 컴파일하면 다음 오류가 발생합니다.

t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
    return p >= 0;
             ^

이 컴파일러 동작은 모든 /std 모드에서 /permissive- 를 사용하여 컴파일된 코드에 영향을 미치는 소스 및 호환성이 손상되는 이진 변경입니다.

참조

Microsoft C/C++ 언어 규칙