Улучшения соответствия C++, изменения в поведении и исправления ошибок в Visual Studio 2022
В каждом выпуске Microsoft C/C++ в Visual Studio (MSVC) добавляются улучшения соответствия и исправления ошибок. В этой статье перечислены значительные улучшения по основным выпускам, а затем по версии. Чтобы перейти непосредственно к изменениям для конкретной версии, используйте ссылки на статью "В этой статье ".
В этом документе перечислены изменения в Visual Studio 2022.
Сведения об изменениях в Visual Studio 2019 см. в улучшениях соответствия C++ в Visual Studio 2019.
Изменения в Visual Studio 2017 см. в статье Улучшения соответствия C++ в Visual Studio 2017.
Сведения об изменениях в более ранних версиях см. в статье Visual C++ What's New 2003–2015.
Улучшения соответствия в 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
На P2286R8range_formatter
теперь реализовано. Эта функция доступна при компиляции с /std:c++latest
помощью .
Улучшения соответствия в Visual Studio 2022 версии 17.10
Visual Studio 2022 версии 17.10 имеет следующие улучшения соответствия, исправления ошибок и изменения поведения в компиляторе Microsoft C/C++.
Подробные сведения об изменениях, внесенных в стандартную библиотеку шаблонов, включая изменения соответствия, исправления ошибок и улучшения производительности, см . в статье STL Changelog 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
Добавлена поддержка РГ21 P2334R1 (C++23) и WG14 N2645 (C++23), которые ввели #elifdef
директивы и #elifndef
директивы препроцессора.
Требуется /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
Применение структурированного _Alignas
типа в C
Применяется к языку C (C17 и более поздним версиям). Также добавлено в Microsoft Visual Studio 17.9
В версиях Visual C++ до Visual Studio 2022 версии 17.9, если _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
со смещением 32 байта в типе struct Outer
.
Это двоичное критическое изменение, поэтому предупреждение теперь создается, когда это изменение вступает в силу. Предупреждение C5274 теперь создается на уровне предупреждения 1 для предыдущего примера: 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))
. declspec(align)
В отличие от _Alignas
типа.
Улучшено предупреждение 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 Changelog VS 2022 17.9.
Применение структурированного _Alignas
типа в C
В версиях Visual C++ до Visual Studio 2022 версии 17.9, когда _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
. Однако до выпуска 17.9.1 Visual Studio была создана диагностика "неправильное выравнивание". Компилятор выровнен member2
с смещением 32 байтов в пределах struct Outer
.
Исправление этого является двоичным критическим изменением, поэтому при применении этого изменения возникает предупреждение. В приведенном выше коде предупреждение 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
formattable
, ,range_format
format_kind
иset_debug_format()
как часть P2286R8 диапазонов форматирования<mdspan>
в P0009R18 и последующих изменениях формулировки, которые были применены к стандарту C++23.format()
указатели на P2510R3.
Улучшения соответствия в Visual Studio 2022 версии 17.8
Visual Studio 2022 версии 17.8 содержит следующие улучшения соответствия, исправления ошибок и изменения поведения в компиляторе Microsoft C/C++.
/FU
проблемы с ошибкой
Компилятор C, используемый для принятия /FU
параметра, даже если он не поддерживает управляемую компиляцию в течение некоторого времени. Теперь она выдает ошибку. Проекты, которые передают этот параметр, должны ограничить его только проектами C++/CLI.
стандартная библиотека C++
Именованные модули std
C++23 и std.compat
теперь доступны при компиляции с /std:c++20
помощью .
Более широкая сводка изменений, внесенных в стандартную библиотеку C++, см. в статье STL Changelog VS 2022 17.8.
Улучшения соответствия в Visual Studio 2022 версии 17.7
Visual Studio 2022 версии 17.7 содержит следующие выделенные улучшения соответствия, исправления ошибок и изменения поведения в компиляторе Microsoft C/C++.
Добавлен /std:clatest
в компилятор C
Этот параметр ведет себя как /std:c++latest
переключатель для компилятора C++. Этот коммутатор включает все реализованные в настоящее время функции компилятора и стандартной библиотеки, предлагаемые для следующего проекта стандарта C, а также некоторые текущие и экспериментальные функции.
стандартная библиотека C++
Теперь <print>
библиотека поддерживается. См . P2093R14 форматированные выходные данные.
Реализовано views::cartesian_product
.
Более широкая сводка изменений, внесенных в стандартную библиотеку шаблонов, см. в статье STL Changelog VS 2022 17.7.
using
соответствие
Ранее директива using
может привести к тому, что имена из используемых пространств имен остаются видимыми, когда они не должны. Это может привести к поиску неквалифицированного имени в пространстве имен, даже если директива не using
активна.
Ниже приведены некоторые примеры нового и старого поведения.
Ссылки на следующие примечания к "(1)" означают вызов f<K>(t)
в пространстве A
имен:
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 компилятора отклоняет его. Чтобы исправить его, добавьте const
, чтобы operator==
удалить неоднозначность. Или добавьте соответствующее 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 до Visual Studio 2022 версии 17.4 компилятор C++ не правильно определил базовый тип неуправляемого перечисления без фиксированного базового типа. В разделе /Zc:enumTypes
теперь мы правильно реализуем стандартное поведение.
Стандарт C++ требует наличия достаточно большого enum
базового типа для хранения всех перечислителей.enum
Достаточно крупные перечислители могут задать базовый enum
unsigned int
тип для , long long
или unsigned long long
. Ранее такие enum
типы всегда имели базовый тип int
в компиляторе Майкрософт независимо от значений перечислителя.
При включении этот /Zc:enumTypes
параметр является потенциальным источником и двоичным критическим изменением. Он отключен по умолчанию и не включен /permissive-
, так как исправление может повлиять на совместимость двоичных файлов. Некоторые типы перечисления изменяют размер при включении соответствующего исправления. Некоторые заголовки пакета SDK для Windows включают такие определения перечисления.
Пример
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 до Visual Studio 2022 версии 17.4 компилятор C++ не правильно моделировал типы перечислителей. Он может предположить неправильный тип перечисления без фиксированного базового типа перед закрывающей скобкой перечисления. В разделе /Zc:enumTypes
компилятор теперь правильно реализует стандартное поведение.
Стандарт C++ указывает, что в определении перечисления не фиксированного базового типа инициализаторы определяют типы перечислителей. Или для перечислителей без инициализатора по типу предыдущего перечислителя (учет переполнения). Ранее такие перечислители всегда были даны выводимый тип перечисления с заполнителем базового типа (обычно int
).
При включении этот /Zc:enumTypes
параметр является потенциальным источником и двоичным критическим изменением. Он отключен по умолчанию и не включен /permissive-
, так как исправление может повлиять на совместимость двоичных файлов. Некоторые типы перечисления изменяют размер при включении соответствующего исправления. Некоторые заголовки пакета SDK для Windows включают такие определения перечисления.
Пример
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 добавлено предупреждение C5255 уровня 3 для незавершенных двунаправленных символов Юникода в комментариях и строках. Предупреждение касается проблемы безопасности, описанной в статье, посвященной программам-троянам (невидимые уязвимости) Николаса Баучера (Nicholas Boucher) и Росса Андерсона (Ross Anderson). Дополнительные сведения о двунаправленных символах Unicode см. в приложении № 9 к стандарту Unicode® с описанием двунаправленного алгоритма Юникода.
Предупреждение C5255 касается только файлов, которые после преобразования содержат двунаправленные символы Unicode. Это предупреждение относится к файлам UTF-8, UTF-16 и UTF-32, поэтому необходимо указать правильную исходную кодировку. Это критическое изменение исходного кода.
Пример (до и после)
В версиях Visual Studio до Visual Studio 2022 версии 17.2 незавершенный двунаправленный символ не вызывал предупреждения. В 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
в узком диапазоне. (Наименьшие и самые крупные затронутые значения были 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__
предоставляет __STDC__
для C
Стандарт C требует, чтобы соответствующая реализация C определяла __STDC__
как 1
. Из-за поведения UCRT без предоставления функций POSIX, когда __STDC__
равно 1
, невозможно определить этот макрос для 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 и более поздних версиях компилятор обнаруживает, когда по умолчанию запись не разрешена в нелокальном лямбда-выражении. Выдается новое предупреждение C5253 уровня 4.
Это критическое изменение исходного кода. Оно применяется в любом режиме, в котором используется новый лямбда-процессор: /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++ было непреднамеренно разрешено упорядоченное сравнение указателей с nullptr
или 0. Например:
bool f(int *p)
{
return p >= 0;
}
В документе WG21 №3478 эта ошибка была исправлена. Это изменение реализуется в MSVC. Когда пример компилируется с помощью /permissive-
(и /diagnostics:caret
), возвращается следующая ошибка:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Это поведение компилятора является критическим изменением исходного и двоичного кодов и влияет на код, скомпилированный с помощью /permissive-
во всех /std
режимах.