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 Studio 2003 から 2015 の Visual C++ の最新情報」を参照してください。
Visual Studio 2022 バージョン 17.11 の準拠の機能強化
Visual Studio 2022 バージョン 17.11 には、Microsoft C/C++ コンパイラでの次の準拠の機能強化、バグ修正、動作の変更があります。
準拠の変更、バグ修正、パフォーマンスの向上など、標準テンプレート ライブラリに加えられた変更の詳細な概要については、 STL Changelog VS 2022 17.11 を参照してください。
空白行を印刷する println
P3142R0ごとに、println
を含む空白行を簡単に生成できるようになりました。 この機能は、 /std:c++latest
を使用してコンパイルするときに使用できます。
この変更の前に、次のように記述しました: println("");
今すぐ記述します: println();
。
println();
はprintln(stdout);
と同じです。println(FILE* stream);
はprintln(stream, "\n");
と同じです。
実装 range_formatter
P2286R8ごとに、range_formatter
が実装されるようになりました。 この機能は、 /std:c++latest
を使用してコンパイルするときに使用できます。
Visual Studio 2022 バージョン 17.10 の準拠の強化
Visual Studio 2022 バージョン 17.10 には、Microsoft C/C++ コンパイラでの次の準拠の機能強化、バグ修正、および動作の変更が含まれています。
準拠に関する変更、バグ修正、パフォーマンスの向上など、標準テンプレート ライブラリに加えられた変更の詳細の要約については、STL の変更ログ VS 2022 17.10 を参照してください。
明示的に指定された戻り値の型での変換演算子の特殊化
コンパイラが変換演算子を誤って特殊化していたため、戻り値の型が一致しないことがありました。 このような無効な特殊化が行われなくなりました。 これはソース コードの破壊的変更です。
// Example 1
struct S
{
template<typename T> operator const T*();
};
void test()
{
S{}.operator int*(); // this is invalid now
S{}.operator const int*(); // this is valid
}
// Example 2
// In some cases, the overload resolution result may change
struct S
{
template <typename T> operator T*(); // overload 1
template <typename T> operator const T*(); // overload 2
};
void test()
{
S{}.operator int*(); // this used to call overload 2, now it calls overload 1
}
#elifdef
および #elifndef
のサポートの追加
#elifdef
および #elifndef
プリプロセッサ ディレクティブを導入した WG21 P2334R1 (C++23) と WG14 N2645 (C++23) のサポートが追加されました。
/std:clatest
または /std:c++latest
が必要です。
以前:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
以後:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
C の構造化型への _Alignas
の適用
C 言語 (C17 以降) に適用されます。 Microsoft Visual Studio 17.9 にも追加されました
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 より前は、"正しくない配置" という診断が生成されました。 コンパイラでは member2
が、struct Outer
型内の 32 バイトのオフセットに配置されました。
これはバイナリの破壊的変更であるため、この変更が有効になったときに、警告が生成されるようになりました。 前の例に対しては、警告レベル 1 で警告 C5274 warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
が生成されます。
また、以前のバージョンの 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)
は型に適用されます。
改善された警告 C4706
これはソース コードの破壊的変更です。 以前のコンパイラは、代入が意図されるものであったときに、その代入をかっこで囲んで条件付き式内の代入に関する警告 C4706 を抑制する規則を検出しませんでした。 現在コンパイラは、かっこを検出し、その警告を抑制します。
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
また、関数が参照されていない場合に、警告を生成するようになりました。 以前は、mf
は参照されないインライン関数であるため、このコードに対して警告 C4706 は生成されませんでした。 今はこの警告が生成されます。
error C4706: assignment used as a condition
note: if an assignment is intended you can enclose it in parentheses, '(e1 = e2)', to silence this warning
この警告を修正するには、それが意図されたものである場合は、等値演算子 value == 9
を使用します。 また、代入が意図されたものである場合は、その代入をかっこで囲みます ((value = 9)
)。 それ以外の場合、関数は参照されないので、削除します。
Visual Studio 2022 バージョン 17.9 の準拠の強化
Visual Studio 2022 バージョン 17.9 には、Microsoft C/C++ コンパイラでの次の準拠の機能強化、バグ修正、および動作の変更が含まれています。
標準テンプレート ライブラリ に加えられた変更の概要については、STL 変更ログ 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 リリースより前は、"正しくない配置" という診断が生成されました。 コンパイラでは member2
が、struct Outer
内の 32 バイトのオフセットに配置されました。
この修正はバイナリの破壊的変更であるため、この動作の変更が適用されると、警告が生成されます。 前のコードに対して、警告 C5274 "_Alignas
は型 "Inner" に適用されなくなりました (宣言されたデータ オブジェクトにのみ適用されます)" が警告レベル 1 で生成されるようになりました。
以前のバージョンの 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 に追加されました。 これが追加される前は、可変個引数のマクロでコンマを省略する標準的な方法はありませんでした。 下位互換性を向上させるために、__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
コンパイラ スイッチを使用すると、以下を使用できます。
以下は、すべての C 言語バージョンで使用できます。
C++ 標準ライブラリ
C++23 の機能
- P2286R8 範囲の書式設定の一部としての
formattable
、range_format
、format_kind
、およびset_debug_format()
- C++23 標準に適用された P0009R18 および後続の表現の変更に応じた
<mdspan>
。 - P2510R3 に応じた
format()
ポインター。
Visual Studio 2022 バージョン 17.8 での準拠の機能強化
Visual Studio 2022 バージョン 17.8 には、Microsoft C/C++ コンパイラでの次の準拠の機能強化、バグ修正、および動作の変更が含まれています。
/FU
でエラーが発生する
C コンパイラは、しばらくの間マネージド コンパイルをサポートしていないにもかかわらず、 /FU
オプションを受け入れていました。 エラーが発生するようになりました。 このオプションを渡すプロジェクトでは、C++/CLI プロジェクトのみに制限する必要があります。
C++ 標準ライブラリ
/std:c++20
を使用してコンパイルするときに、C++23 の名前付きモジュール std
と std.compat
を使用できるようになりました。
C++ Standard ライブラリに加えられた変更のより広範な概要については、STL Changelog VS 2022 17.8 を参照してください。
Visual Studio 2022 バージョン 17.7 の準拠の機能強化
Visual Studio 2022 バージョン 17.7 には、Microsoft C/C++ コンパイラでの次の強調表示された準拠の機能強化、バグ修正、および動作の変更が含まれています。
/std:clatest
を C コンパイラに追加しました
このスイッチは、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
である必要があります。そのため、B
は sizeof(char)
を使って初期化する必要があります。 /Zc:enumTypes
の修正前は、A
は列挙型 Enum
であり、推論される基となる型は int
でした。B
は sizeof(Enum)
(つまり 4) を使って初期化されていました。
Visual Studio 2022 バージョン 17.3 の準拠の強化
Visual 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 では、コメントと文字列での未終了の Unicode 双方向文字に対してレベル 3 の警告 C5255 が追加されます。 この警告は、Nicholas Boucher 氏と Ross Anderson 氏による「Trojan Source: Invisible Vulnerabilities (トロイの木馬のソース: 目に見えない脆弱性)」で説明されているセキュリティ上の懸念に対処するものです。 Unicode 双方向文字の詳細については、「Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM (Unicode® 標準の付属書 #9: Unicode 双方向アルゴリズム)」を参照してください。
警告 C5255 で対処されるのは、変換後に Unicode 双方向文字を含むファイルのみです。 この警告は 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 進数値文字列に影響を与えました。 (影響を受ける値の最小値と最大値はそれぞれ 32768.009765625
と 131071.98828125
でした。)タイブレーカー ルールは "偶数" に丸めようとし、"偶数" は "切り下げ" でしたが、実装は誤って "切り上げ" られました (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 の今後のバージョンでは、既定でこのオプションが使用される予定です。
この変更は、ソースの破壊的変更です。 これは、C11 または C17 モードが有効で (/std:c11
または /std:c17
)、/Zc:__STDC__
が指定されている場合に適用されます。
例
// 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 コードにおける特定の関数からポインターへの比較で、コンパイラから正しくないエラー メッセージが報告されました。 引数の数は同じでも型に互換性のない 2 つの関数ポインターを比較すると、正しくないメッセージが報告されました。 今回、関数パラメーターの不一致ではなく、関数へのポインターの非互換性を示す別の警告が発行されるようになりました。
この変更は、ソースの破壊的変更です。 これは、コードが 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++ 標準では、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-
を使用してコンパイルされたコードに影響します。