C++17 структурированные привязки, контейнеры и новые типы


Оглавление (нажмите, чтобы открыть):

Какие типы идентификаторов введены структурированными привязками в C ++ 17?

Насколько мне известно, идентификаторы, представленные структурированными привязками в C ++ 17, на самом деле являются ссылками на некоторую «скрытую» переменную. Такой, что

является вид эквивалентно

Тем не менее, если я распечатаю std::is_reference ::value , Я получил 0 в первом случае 1 во-вторых. Это почему?

Решение

если я распечатаю std::is_reference ::value Я получаю 0 в первом случае 1 во втором.

Почему, даже если мы можем доказать это? a а также b обратитесь к элементам в кортеже, и с помощью них можно изменить эти значения?
Я не адвокат по языкам, но, вероятно, это связано с эта пуля стандарта (рабочий проект):

если e это не заключенное в скобки id-выражение, обозначающее структурированную привязку […], decltype(e) ссылочный тип, указанный в спецификации объявления структурированной привязки

Примечание. Вы должны использовать эту форму для того, чтобы a а также b обратитесь к элементам в кортеже:

Следует минимальный рабочий пример:

Смотрите это на Coliru . С другой стороны, что вы получаете копия ценностей используя выражение ниже:

Вот это статья, которая объясняет это лучше и немного более понятна, чем стандарт для люди.

Другие решения

Насколько мне известно, идентификаторы, представленные структурированными привязками в C ++ 17, на самом деле являются ссылками на некоторую «скрытую» переменную.

Если под «ссылкой» вы подразумеваете ссылку на языковую конструкцию, это не совсем правильно. Спецификаторы в объявлении относятся к «скрытой переменной», о которой вы говорите. Ссылочный квалификатор не является обязательным. Код, который вы представили, будет выглядеть примерно так:

Каковы типы идентификаторов, введенных структурированными привязками в С++ 17?

Насколько я знаю, идентификаторы, введенные структурированными связями в С++ 17, фактически ссылаются на некоторую «скрытую» переменную. Таким образом,

является своего рода эквивалентом

Однако, если я распечатаю std::is_reference ::value , я получаю 0 в первом случае 1 во втором. Почему это?

c++ reference c++1z decltype c++17 structured-bindings

2 ответа

9 Решение skypjack [2020-06-21 12:34:00]

если я распечатаю std::is_reference ::value , я получаю 0 в первом случае 1 во втором.

Почему это, даже если мы можем доказать, что a и b относятся к элементам в кортеже, и с их помощью можно изменять эти значения?
Я не юрист по языку, но, вероятно, это связано с этой маркой стандартного (рабочий проект):

if e — это несферированное id-выражение, называющее структурированное связывание [. ], decltype(e) является ссылочным типом, как указано в спецификации объявления структурированного связывания

Боковое примечание. Вы должны использовать эту форму, чтобы a и b относились к элементам в кортеже:

Это следует за минимальным рабочим примером:

Посмотрите на Coliru. С другой стороны, вы получаете копию значений, используя следующее выражение:

Здесь — статья, которая объясняет это лучше и немного понятна, чем стандарт для людей.

Насколько я знаю, идентификаторы, введенные структурированными связями в С++ 17, фактически ссылаются на некоторую «скрытую» переменную.

Если по ссылке ссылается ссылка на язык, это не совсем правильно. Специфика в декларации относится к «скрытой переменной», о которой вы говорите. Контрольный квалификатор необязателен. Представленный вами код будет более похож на этот:

Какие типы идентификаторов вводятся структурированными привязками в C++17?

насколько мне известно, идентификаторы, введенные структурированными привязками в C++17, на самом деле являются ссылками на некоторую «скрытую» переменную. Такой, что

is рода эквивалентно

однако, если я распечатаю std::is_reference ::value , Я 0 в первом случае 1 во втором. Почему так?

2 ответов

если я распечатаю std::is_reference ::value , Я получаю 0 в первом случае 1, во втором.

почему это, даже если мы можем доказать, что a и b обратитесь к элементам кортежа, и с их помощью можно изменить эти значения?
Я не языковой юрист, но, вероятно, это связано с пуля стандартного (рабочего проекта):

если e является непарентированным id-выражением, называющим структурированную привязку [. ], decltype(e) является ссылочным типом, как указано в спецификации структурированного объявления привязки

Примечание. Вы должны использовать эту форму, чтобы сделать это a и b обратитесь к элементам кортежа:

это следует за минимальным, рабочим примером:

см. На Coliru. С другой стороны, вы получаете копия значения используя выражение ниже:

здесь это статья, которая объясняет это лучше и немного более понятна, чем стандарт для люди.

насколько мне известно, идентификаторы, введенные структурированными привязками в C++17, на самом деле являются ссылками на некоторую «скрытую» переменную.

Если под «ссылкой» Вы подразумеваете ссылку на языковую конструкцию, это не совсем правильно. Спецификаторы в объявлении относятся к» скрытой переменной», о которой вы говорите. Квалификатор ссылки является необязательным. Код, который вы представили, был бы больше похож на это:

Комитет ISO утвердил спецификацию С++17

Комитет ISO по языку C++ единогласно утвердил спецификацию C++17. Теперь она формально является международным стандартом. Новые возможности уже есть в компиляторах GCC и clang, а также частично присутствуют в Intel C++ и Visual C++.

Работа над стандартом была завершена ещё в марте этого года. С тех пор происходила формальная процедура подтверждения, было внесено небольшое количество изменений. В результате голосования комиссии работа получила 23 замечания, все они не технического характера.

В течение следующих двух месяцев будет проходить подготовка документа к публикации, где будут исправлены все опечатки и ошибки. В начале ноября окончательный вариант документа будет направлен в ISO для публикации под формальным именем ISO/IEC 14882:2020. Комитет уже начал работу над следующим стандартом C++20.

Подборка материалов по C/C++ —

Подборка материалов по C/C++

— C++17: структурированные привязки, контейнеры и новые типы
https://prglb.ru/4n2py

— Большой список упражнений по С++ для начинающих разработчиков
https://www.geeksforgeeks.org/c-plus-plus/

— Библиотека для реактивного программирования на C++11
https://github.com/schlangster/cpp.react

— Обзор принципа KISS на примере решения алгоритмических задач
https://prglb.ru/40i58

— Пишем юнит-тесты для С++ приложений с использованием Google Test
https://www.youtube.com/watch?v=16FI1-d2P4E

Во вложении вы найдете шпаргалку по основам синтаксиса в C++

А если хотите получать больше материалов по теме, то не забудьте подписаться на канал tgmsg.ru/cppproglib

А здесь можно найти актуальные вакансии по C++ tgmsg.ru/cppdevjob

C++17: структурированные привязки, контейнеры и новые типы

C++17: структурированные привязки, контейнеры и новые типы

Язык C++ постоянно развивается, и нам как разработчикам статического анализатора важно следить за всеми изменениями, чтобы поддерживать все новые возможности языка. В этой обзорной статье я хотел бы поделиться с читателем наиболее интересными нововведениями, появившимися в C++17, а также продемонстрировать их на примерах.

Сейчас поддержка нового стандарта активно добавляется разработчиками компиляторов. Посмотреть, что поддерживается на текущий момент, можно по ссылкам:

Свертка параметров шаблона (Fold expressions)

Для начала несколько слов о том, что вообще такое свертка списка (также известна как fold, reduce или accumulate).

Свертка – это функция, которая применяет заданную комбинирующую функцию к последовательным парам элементов в списке и возвращает результат. Простейшим примером может служить суммирование элементов списка при помощи свертки:

Если комбинирующая функция применяется к первому элементу списка и результату рекурсивной обработки хвоста списка, то свертка называется правоассоциативной. В нашем примере получим:

Если комбинирующая функция применяется к результату рекурсивной обработки начала списка (весь список без последнего элемента) и последнему элементу, то свертка называется левоассоциативной . В нашем примере получим:

Таким образом, тип свертки определяет порядок вычислений.

В C++17 появилась поддержка свертки для списка параметров шаблонов. Она имеет следующий синтаксис:

Унарная правоассоциативная свертка

Унарная левоассоциативная свертка

(pack op . op init)

Бинарная правоассоциативная свертка

(init op . op pack)

Бинарная левоассоциативная свертка

op – один из следующих бинарных операторов:

pack – выражение, содержащее нераскрытую группу параметров (parameter pack)

init – начальное значение

Вот, например, шаблонная функция, принимающая переменное число параметров и вычисляющая их сумму:

Примечание: В данном примере функцию Sum можно было бы объявить как constexpr .

Если мы хотим указать начальное значение, то используем бинарную свертку:

До C++17 чтобы реализовать подобную функцию, пришлось бы явно указывать правила для рекурсии:

Отдельно хочется отметить оператор ‘,’ (запятая), который раскроет pack в последовательность действий, перечисленных через запятую. Пример:

Таким образом, свертка сильно упрощает работу с variadic templates.

template

Теперь в шаблонах можно писать auto для non-type template параметров. Например:

Ранее единственным способом передать non-type template параметр с неизвестным типом была передача двух параметров – типа и значения. Другими словами, ранее этот пример выглядел бы следующим образом:

Вывод типов шаблонных параметров для классов

До C++17 вывод типов шаблонных параметров работал только для функций, из-за чего при конструировании шаблонного класса всегда было нужно в явном виде указывать шаблонные параметры:

либо использовать специализированные функции вроде std::make_pair , для неявного вывода типов:

Связано это было с тем, что достаточно сложно осуществить такой вывод при наличии нескольких конструкторов в классе. В новом стандарте эта проблема была решена:

Стандартом было определено множество правил вывода типов (deduction guides). Также предоставляется возможность самим писать эти правила, например:


Большинство стандартных контейнеров работают без необходимости вручную указывать deduction guide .

Примечание: компилятор может вывести deduction guide автоматически из конструктора, но в данном примере у структуры S нет ни одного конструктора, поэтому и определяем deduction guide вручную.

Таким образом, вывод типов для классов позволяет значительно сократить код и забыть о таких функциях как std::make_pair , std::make_tuple, и использовать вместо них конструктор.

Constexpr if

В C++17 появилась возможность выполнять условные конструкции на этапе компиляции. Это очень мощный инструмент, особенно полезный в метапрограммировании. Приведу простой пример:

До C++17 нам пришлось бы использовать SFINAE и enable_if :

Не трудно заметить, что код с constexpr if на порядок читабельнее.

Constexpr лямбды

До C++17 лямбды не были совместимы с constexpr . Теперь лямбды можно писать внутри constexpr выражений, а также можно объявлять сами лямбды как constexpr .

Примечание: даже если спецификатор constexpr не указан, лямбда все равно будет constexpr , если это возможно.

Пример с лямбдой внутри constexpr функции:

Пример с constexpr лямбдой:

Захват *this в лямбда-выражениях

Теперь лямбда-выражения могут захватывать члены класса по значению при помощи *this :

inline переменные

В C++17 в дополнение к inline функциям появились также inline переменные. Переменная или функция, объявленная inline, может быть определена (обязательно одинаково) в нескольких единицах трансляции.

inline переменные могут пригодиться разработчикам библиотек, состоящих из одного заголовочного файла. Приведу небольшой пример:

(Вместо того, чтобы писать extern и присваивать значение в .cpp)

До C++17 пришлось бы объявлять переменную MyVar как extern и в одном из .cpp файлов присваивать ей значение.

Структурное связывание (Structured bindings)

Появился удобный механизм для декомпозиции таких объектов, как, например, пары или кортежи, называемый Structured bindings или Decomposition declaration.

Продемонстрирую его на примере:

Метод insert() возвращает pair , где iterator является итератором на вставленный объект и bool , который принимает значение false , если элемент не был вставлен (т.е. уже содержался в mySet ).

До C++17 нужно было бы использовать std::tie :

Очевидным недостатком является то, что переменные iter и ok приходится объявлять заранее.

Помимо этого, структурное связывание можно использовать с массивами:

Можно также производить декомпозицию типов, содержащих только нестатические открытые члены.

На мой взгляд, очень удачным применением структурного связывания является его использование в range-based циклах:

Инициализатор в if и switch

В C++17 появились операторы if и switch с инициализатором:

Они удачно смотрятся в связке с упомянутым выше структурным связыванием. Например:

__has_include

Предикат препроцессора __has_include позволяет проверить, доступен ли заголовочный файл для подключения.

Приведу пример использования прямо из предложения к стандарту (P0061R1). Здесь подключаем optional если он доступен:

Новые атрибуты

В дополнение к уже существующим стандартным атрибутам [[noreturn]] , [[carries_dependency]] и [[deprecated]] в C++17 появились 3 новых атрибута:

Этот атрибут показывает, что оператор break внутри блока case отсутствует намеренно (т.е. управление передается в следующий блок case), и поэтому соответствующее предупреждение компилятора или статического анализатора кода выдаваться не должно.

Этот атрибут используется, чтобы обозначить, что возвращаемое значение функции должно быть обязательно использовано при вызове:

Также [[nodiscard]] можно применять к типам данных или перечислениям, чтобы пометить все функции, возвращающие этот тип как [[nodiscard]] :

Этот атрибут используется, чтобы подавить предупреждения компилятора/анализатора о неиспользуемой переменной, параметре функции, статической функции и прочем. Примеры:

Новый тип std::byte

Тип std::byte предлагается использовать при работе с ‘сырой’ памятью. Обычно для этого используется char , unsigned char или uint8_t . Тип std::byte является более типобезопасным, так как к нему можно применить только побитовые операции, а арифметические операции и неявные преобразования недоступны. Другими словами, указатель на std::byte не удастся использовать в качестве фактического аргумента для вызова функции F(const unsigned char *) .

Этот новый тип определен в следующим образом:

Динамическое выделение памяти для типов с нестандартным выравниванием (Dynamic allocation of over-aligned types)

В C++11 был добавлен спецификатор alignas , позволяющий вручную указать выравнивание для типа или переменой. До C++17 не было никаких гарантий того, что выравнивание будет выставлено в соответствии с alignas при динамическом выделении памяти. Теперь же стандарт гарантирует, что выравнивание будет учитываться:

Более строгий порядок вычисления выражений

В C++17 появились новые правила, более строго определяющие порядок вычисления выражений:

  • Постфиксные выражения вычисляются слева направо (в том числе вызовы функций и доступ к членам объектов)
  • Выражения присваивания вычисляются справа налево.
  • Операнды операторов и >> вычисляются слева направо.

Таким образом, как указывается в предложении к стандарту, в следующих выражениях теперь гарантированно сначала вычисляется a , затем b , затем c , затем d :

Обратите внимание, что порядок выполнения между b1 , b2 , b3 по-прежнему не определен. Приведу один хороший пример из предложения к стандарту:

Это код из книги Страуструпа «The C++ Programming Language, 4th edition», который использовался для демонстрации вызова методов «по цепочке». Ранее этот код имел unspecified behavior, однако начиная с C++17, он будет работать как и задумывалось. Дело в том, что неизвестно какая из функций find будет вызвана первой.

Т.е. теперь в выражениях вида:

Подвыражения subexpr1 , subexpr2 , subexpr3 , subexpr4 вычисляются согласно порядку вызова функций F1 , F2 , F3 , F4 . Ранее порядок вычисления таких подвыражений не был определен, что приводило к ошибкам.

Filesystem

C++17 предоставляет возможности для кроссплатформенной работы с файловой системой. Эта библиотека фактически является boost::filesystem , которую перенесли в стандарт.

Рассмотрим несколько примеров работы с std::filesystem .

Заголовочный файл и пространство имен:

Работа с объектом fs::path:

Работа с директориями:

Возможные значения fs::copy_options для обработки уже существующих файлов представлены в таблице:

Если файл уже существует, выбрасывается исключение. (Значение по умолчанию)

Существующие файлы не перезаписываются, исключение не выбрасывается.

Существующие файлы перезаписываются.

Существующие файлы перезаписываются, только более новыми файлами.

Работа с файлами:

Это далеко не полный список возможностей std::filesystem . Со всеми возможностями можно ознакомиться здесь.

std::optional

Это шаблонный класс, который хранит опциональное значение. Его удобно использовать, чтобы, например, возвращать значение из функции, в которой может произойти какая-то ошибка:

Еще у std::optional имеется метод value_or , который возвращает значение из optional , если оно доступно или иное установленное значение в противном случае.

std::any

Объект класса std::any может хранить информацию любого типа. Так, одна и та же переменная типа std::any может сначала хранить int , затем float , а затем строку. Пример:

Стоит отметить, что std::any не производит никаких привидений типов, что позволяет избежать неоднозначности. По этой причине, в примере явно указывается тип std::string , т.к. в противном случае в объекте std::any будет храниться простой указатель.

Чтобы получить доступ к информации, хранящейся в объекте std::any , нужно воспользоваться std::any_cast . Например:

Если в качестве шаблонного параметра std::any_cast был передан любой тип, отличный от типа текущего хранимого объекта, будет выброшено исключение std::bad_any_cast .

Информацию о хранящемся типе можно получить с помощью метода type() :

std::variant

std::variant — это шаблонный класс, который представляет собой union , который помнит, какой тип он хранит. Также, в отличие от union , std::variant позволяет хранить non-POD типы.

Для получения значений из std::variant используется функция std::get . Она выбросит исключение std::bad_variant_access, если попытаться взять не тот тип.

Также имеется функция std::get_if , которая принимает указатель на std::variant и возвращает указатель на текущее значение, если тип был указан правильно, и nullptr в противном случае:

Обычно более удобным способом работы с std::variant является std::visit :

std::string_view

В C++17 появился особый класс – std::string_view , который хранит указатель на начало существующей строки и ее размер. Таким образом, std::string_view представляет собой не владеющую памятью строку.

У std::string_view имеются конструкторы, принимающие std::string , char[N] , char* , поэтому больше нет необходимости писать 3 перегруженные функции:

Теперь во всех функциях, принимающих const std::string&, можно изменить тип на std::string_view , поскольку это позволит повысить производительность для случаев, когда в функцию передается строковый литерал или Си-массив. Это связанно с тем, что при конструировании объекта std::string обычно происходит аллокация памяти, а при конструировании std::string_view никаких аллокаций, естественно, не происходит.

Не стоит изменять тип аргумента функции с const string& на string_view только в том случае, если внутри этой функции вызывается функция с этим аргументом и принимающая const string& .

try_emplace и insert_or_assign

В C++17 у контейнеров std::map и std::unordered_map появились новые функции – try_emplace и insert_or_assign .

В отличие от emplace , функция try_emplace не «крадёт» move-only аргумент, в случае если вставка элемента не произошла. Лучше всего объяснить это на примере:

Если вставка не происходит, из-за того, что элемент с таким ключом уже есть в myMap , try_emplace не «крадёт» строку s1 , в отличие от emplace .

Функция insert_or_assign вставляет элемент в контейнер, если элемента с таким ключом еще нет в контейнере и перезаписывает существующий элемент, если элемент с таким ключом существует. Функция возвращает std::pair , состоящий из итератора на вставленный/перезаписанный элемент и булевого значения, показывающего произошла вставка нового элемента или нет. Таким образом эта функция аналогична operator[] , но возвращает дополнительную информацию о том, была выполнена вставка или перезапись элемента:

До C++17 чтобы выяснить, произошла вставка или обновление приходилось сначала искать элемент, а затем применять operator[] .


Специальные математические функции

В C++17 было добавлено множество специализированных математических функций, таких как: бета-функции, Дзета-функции Римана и прочие. Подробнее о них прочитать можно здесь.

Объявление вложенных пространств имен

В C++17 можно написать:

Неконстантный string::data

В C++17 у std::string появился метод data() , возвращающий неконстантный указатель на внутренние данные строки:

Это будет полезно при работе со старыми Си библиотеками.

Параллельные алгоритмы

Execution policy может принимать одно из 3-х значений:

  • std::execution::seq – последовательное выполнение
  • std::execution::par – параллельное выполнение
  • std::execution::par_unseq – параллельное векторизованное выполнение

Таким образом, чтобы получить многопоточную версию алгоритма, достаточно написать:

Необходимо следить, чтобы накладные расходы на создание потоков не перевесили выгоду от использования многопоточных алгоритмов. Естественно, также программисту самому нужно следить за тем, чтобы не возникало состояний гонки или взаимных блокировок.

Также стоит отметить разницу между std::execution::seq и версией без такого параметра – если в функцию передается execution policy, то в этом алгоритме нельзя выбрасывать исключения, которые выходят за границы функтора. Если выбросить такое исключение, будет вызван std::terminate .

В связи с добавлением параллелизма, появилось несколько новых алгоритмов:

std::reduce – работает аналогично std::accumulate, но порядок свертки строго не определен, поэтому может работать параллельно. Имеет перегрузку, принимающую execution policy. Небольшой пример:

std::transform_reduce – применяет заданный функтор на элементах контейнера, а затем применяет std::reduce .

std::for_each_n – работает аналогично std::for_each , но заданный функтор применяется только к n элементам. Например:

std::invoke, трейт is_invocable

std::invoke принимает на вход сущность, которая может быть вызвана, и набор аргументов и вызывает эту сущность с этими аргументами. Такими сущностями, например, являются указатель на функцию, объект с operator() , лямбда-функция и прочие:

std::invoke может пригодиться в какой-нибудь шаблонной магии. Также в C++17 был добавлен трейт std::is_invocable :

std::to_chars, std::from_chars

В C++17 появились функции std::to_chars и std::from_chars для очень быстрого преобразования чисел в строки и строк в числа соответственно. В отличие от других функций форматирования из C и C++, std::to_chars не зависит от локали, не выделяет память и не выбрасывает исключений, и нацелены на максимальную производительность:

Функция std::to_chars возвращает структуру to_chars_result :

ptr – указатель на последний записанный символ + 1

Функция std::from_chars возвращает структуру from_chars_result :

ptr – указатель на первый символ, не удовлетворяющий паттерну

На мой взгляд, стоит использовать эти функции везде, где нужны преобразования из строки в число и из числа в строку, в случаях, когда вам достаточно Си-локали, т.к. это даст неплохой прирост производительности.

std::as_const

Вспомогательная функция std::as_const принимает на вход ссылку и возвращает ссылку на константу:

Свободные функции std::size, std::data и std::empty

В дополнение к уже существующим свободным функциям std::begin , std::end и прочим появились свободные функции std::size , std::data и std::empty :

std::clamp

В C++17 появилась функция std::clamp(x, low, high) , которая возвращает x, если он находится в интервале [low, high] или ближайшее из этих значений в противном случае:

НОД и НОК

В стандарте появилось вычисление Наибольшего Общего Делителя ( std::gcd ) и Наименьшего Общего Кратного ( std::lcm ):

Логические метафункции (Logical operation metafunctions)

В C++17 появились логические метафункции std::conjunction , std::disjunction и std::negation . Они используются для того, чтобы выполнить логическое И, ИЛИ, НЕ на наборе трейтов соответственно. Небольшой пример с std::conjunction :

Замечу, что в отличие от свертки параметров шаблона, упомянутой выше, функции std::conjunction и std::disjunction остановят инстанцирование, как только результирующее значение сможет быть определено.

Атрибуты в пространствах имен и перечислениях

Теперь можно использовать атрибуты для пространств имен и для перечислений, а также внутри них:

Префикс using для атрибутов

Добавлен префикс using для атрибутов, поэтому при использовании нескольких атрибутов можно немного сократить запись. Пример из предложения к стандарту (P0028R4):

Возвращаемое значение у emplace_back

Теперь emplace_back возвращает ссылку на вставленный элемент, до C++17 он не возвращал никакого значения:

Функторы для поиска подстроки в строке (Searcher function objects)

В C++17 появились функторы, реализующие поиск подстроки в строке, использующие алгоритм Бойера – Мура или алгоритм Бойера — Мура – Хорспула. Эти функторы можно передавать в std::search :

std::apply

std::apply вызывает сallable-объект с набором параметров, записанным в кортеже. Пример:

Конструирование объектов из кортежей (std::make_from_tuple)

В C++17 появилась возможность сконструировать объект, передав в конструктор набор аргументов, записанных в кортеже. Для этого используется функция std::make_from_tuple :

std::not_fn (Universal negator not_fn)

В C++17 появилась функция std::not_fn , возвращающая предикат-отрицание. Эта функция призвана заменить std::not1 и std::not2:

Доступ к нодам контейнеров (Node handle)

В С++17 появилась возможность перемещать ноду напрямую из одного контейнера в другой. При этом не происходят дополнительные аллокации или копирование. Приведу небольшой пример:

Метод std::extract позволяет извлечь ноду из контейнера, а метод insert теперь также умеет вставлять ноды.

Также в C++17 у контейнеров появился метод merge, который пытается извлечь все ноды контейнера с помощью extract и вставить их в другой контейнер с помощью insert :

Еще одним интересным примером может служить изменение ключа элемента в std::map :

До C++17 избежать дополнительных накладных расходов при изменении ключа было невозможно.

static_assert с одним аргументом

Теперь для static_assert необязательно указывать сообщение:

std::*_v

В C++17 у всех трейтов из , имеющих поле ::value , появились перегрузки вида some_trait_v . Поэтому теперь вместо того, чтобы писать some_trait ::value, можно просто написать some_trait_v . Например:

std::shared_ptr for arrays

Теперь shared_ptr поддерживает C-массивы. Необходимо просто передать T[] шаблонным параметром и shared_ptr вызовет delete[] при освобождении памяти. Ранее для массивов нужно было указывать функцию для удаления вручную. Небольшой пример:

std::scoped_lock

В C++17 появился новый класс scoped_lock , который блокирует несколько мьютексов одновременно (используя lock) при создании и освобождает их всех в деструкторе, предоставляя удобный RAII-интерфейс. Небольшой пример:

Удаленные возможности

  • Были удалены триграфы.
  • Ключевое слово register больше нельзя использовать как спецификатор переменной. Оно остается зарезервированным на будущее, как это было с auto .
  • Были удалены префиксный и постфиксный инкременты для типа bool .
  • Была удалена спецификация исключений. Больше нельзя указать какие именно исключения выбрасывает функция. В C++17 стоит лишь помечать функции, которые не выбрасывают исключений как noexcept .
  • Был удален std::auto_ptr . Вместо него стоит использовать std::unique_ptr .
  • Был удален std::random_shuffle . Вместо него стоит использовать std::shuffle , с соответствующим функтором, генерирующим случайные числа. Удаление связанно с тем, что std::random_shuffle использовал std::rand , который в свою очередь признан устаревшим.

Итоги

К сожалению, в C++17 не вошли ожидаемые всеми модули, концепты, работа с сетью, рефлексия и прочие важные фичи, поэтому с нетерпением ждем C++20.

Для себя, как одного из разработчиков анализатора кода PVS-Studio, могу отметить, что нам предстоит много интересной работы. Новые возможности языка открывают и новые возможности «отстрелить себе ногу», и мы должны научить анализатор предупреждать программиста об ошибках новых разновидностей. Например, в C++14 появилась возможность инициализировать динамический массив при его создании. Следовательно, полезно предупреждать программиста, когда размер динамического массива может оказаться меньше количества элементов в его инициализаторе. Поэтому мы создали новую диагностику V798. Диагностики для новых конструкций языка мы делали и продолжаем делать. Для C++17 будет полезно, например, предупредить, что в алгоритме для std::execution::par используются конструкции, которые могут сгенерировать исключения и эти исключения не будут специально перехвачены внутри алгоритма с помощью try. catch.

Спасибо за внимание. Предлагаю скачать PVS-Studio (Windows/Linux) и проверить свои проекты. Язык C++ становится все «более большим» и все сложнее отследить все аспекты и нюансы его использования, чтобы написать правильный код. PVS-Studio содержит большую базу знаний о том, «что делать нельзя» и будет вам незаменимым помощником. Да и от простых опечаток никто не застрахован и никуда эта проблема не денется. Proof.

Дополнительные ссылки

  • Changes between C++14 and C++17 DIS.
  • Youtube. Полухин Антон | C++17.
  • Youtube. Nicolai Josuttis. С++17. The Language Features. Part 1, Part 2.
  • Herb Sutter. Trip report: Summer ISO C++ standards meeting (Oulu).
  • Bartlomiej Filipek. C++ 17 Features.
Найдите ошибки в своем C, C++, C# и Java коде

Предлагаем попробовать проверить код вашего проекта с помощью анализатора кода PVS-Studio. Одна найденная в нём ошибка скажет вам о пользе методологии статического анализа кода больше, чем десяток статей.

Каковы типы идентификаторов, введенных структурированными привязками в С++ 17?

Насколько я знаю, идентификаторы, введенные структурированными связями в С++ 17, фактически ссылаются на некоторую «скрытую» переменную. Таким образом,


является своего рода эквивалентом

Однако, если я распечатаю std::is_reference ::value , я получаю 0 в первом случае 1 во втором. Почему это?

если я распечатаю std::is_reference ::value , я получаю 0 в первом случае 1 во втором.

Почему это, даже если мы можем доказать, что a и b относятся к элементам в кортеже, и с их помощью можно изменять эти значения? Я не юрист по языку, но, вероятно, это связано с этой маркой стандартного (рабочий проект):

if e — это несферированное id-выражение, называющее структурированное связывание [. ], decltype(e) является ссылочным типом, как указано в спецификации объявления структурированного связывания

Боковое примечание. Вы должны использовать эту форму, чтобы a и b относились к элементам в кортеже:

Это следует за минимальным рабочим примером:

Посмотрите на Coliru. С другой стороны, вы получаете копию значений, используя следующее выражение:

Здесь — статья, которая объясняет это лучше и немного понятна, чем стандарт для людей.

Улучшения соответствия C++ в Visual Studio 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 2020 RTW (версия 16.0) Conformance improvements in Visual Studio 2020 RTW (version 16.0)

Visual Studio 2020 RTW содержит следующие улучшения соответствия, исправления ошибок и изменения в поведении в компиляторе Microsoft C++ (MSVC) Visual Studio 2020 RTW contains the following conformance improvements, bug fixes, and behavior changes in the Microsoft C++ compiler (MSVC)

Примечание. Возможности C ++ 20 будут доступны в режиме /std:c++latest до завершения реализации C++20 для компилятора и IntelliSense. 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 2020 версии 15.9. Improved support was added in Visual Studio 2020 version 15.9. Дополнительные сведения см. в разделе Улучшенная поддержка шаблонов и обнаружение ошибок в модулях C++ MSVC 2020 версии 15.9. For more information, see Better template support and error detection in C++ Modules with MSVC 2020 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 2020 в разделе /std:c++latest класс с любым конструктором, объявленным пользователем (например, конструктор, объявленный = default или = delete ), не является агрегатом. In Visual Studio 2020, 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 2020, но вызывает ошибки C2280 и C2440 в Visual Studio 2020 в /std:c++latest : The following code compiles without errors in Visual Studio 2020 but raises errors C2280 and C2440 in Visual Studio 2020 under /std:c++latest :

Частичная поддержка для operator Partial support for operator

P0515R3 C++20 вводит трехсторонний оператор сравнения , также известный как «оператор — космический корабль». P0515R3 C++20 introduces the three-way comparison operator, also known as the «spaceship operator». Visual Studio 2020 в режиме /std:c++latest вводит частичную поддержку оператора, вызывая ошибки синтаксиса, который сейчас запрещен. Visual Studio 2020 in /std:c++latest mode introduces partial support for the operator by raising errors for syntax that is now disallowed. Например, следующий код компилируется без ошибок в Visual Studio 2020, но вызывает различные ошибки в Visual Studio 2020 в /std:c++latest : For example, the following code compiles without errors in Visual Studio 2020 but raises multiple errors in Visual Studio 2020 under /std:c++latest :

Чтобы избежать этих ошибок, добавьте символ пробела в строку, вызывающую ошибку, перед последней скобкой: U u; . To avoid the errors, insert a space in the offending line before the final angle bracket: U 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. Это делало возможным изменение предположительно постоянных данных, на которые указывала ссылка. 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 2020 следующий код компилировался без предупреждений. In Visual Studio 2020, the following code compiles without warnings. В Visual Studio 2020 компилятор выдает предупреждение C4172: возвращение адреса локальной переменной или временных данных. In Visual Studio 2020, the compiler raises warning C4172: returning address of local variable or temporary.

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 2020, но в Visual Studio 2020 выдает ошибку C2440: невозможно выполнить преобразование из overloaded-function в fp: The following code compiles without errors in Visual Studio 2020, but in Visual Studio 2020 it raises C2440: cannot convert from ‘overloaded-function’ to ‘fp’:

Чтобы избежать этой ошибки, используйте допустимые приведения для этого сценария: To avoid the error, use an allowed cast for this scenario:

Замыкания лямбда-выражений 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 2020, но в Visual Studio 2020 он вызывает ошибку C2127: l: недопустимая инициализация сущности «constexpr» с неконстантным выражением: The following code compiles without errors in Visual Studio 2020, but in Visual Studio 2020 it raises C2127: ‘l’: illegal initialization of ‘constexpr’ entity with a non-constant expression:

Чтобы избежать этой ошибки, удалите квалификатор 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

Безусловная реализация P1164 из C ++ 20. 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 были включены в коды «Выполнено успешно, но каталог не создан». Previously, all ERROR_ALREADY_EXISTS type errors were turned into success-but-directory-not-created codes.

operator

Для LWG 2221 добавлен operator для записи nullptrs в потоки. Per LWG 2221, added operator for writing nullptrs to streams.

Дополнительные параллельные алгоритмы Additional parallel algorithms

Новые параллельные версии is_sorted , is_sorted_until , is_partitioned , set_difference , set_intersection , is_heap и is_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. Это исправление включается при использовании 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_cvref и remove_cvref_t remove_cvref and remove_cvref_t

Реализация признаков типа remove_cvref и remove_cvref_t из P0550. Implemented the remove_cvref and remove_cvref_t type traits from P0550. Они удаляют ссылочность и cv-квалификацию из типа без ограничения функций и массивов до указателей (в отличие от std::decay и std::decay_t ). 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 — макросы тестирования функций завершены с поддержкой __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++ в 16.1 Conformance improvements in 16.1

char8_t char8_t

P0482r6. P0482r6. C ++ 20 добавляет новый тип символа, который используется для представления частей кода UTF-8. C++20 adds a new character type that is used to represent UTF-8 code units. Строковые литералы u8 в C++20 имеют тип const char8_t[N] , а не const char[N] , как было раньше. u8 string literals in C++20 have type const char8_t[N] instead of const char[N] , which was the case previously. Аналогичные изменения предложены для стандарта C в N2231. 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++ добавляет поддержку char8_t в Visual Studio 2020 версии 16.1, если вы укажете параметр компилятора /Zc:char8_t. The Microsoft C++ compiler adds support for char8_t in Visual Studio 2020 version 16.1 when you specify the /Zc:char8_t compiler option. В будущем он будет поддерживаться с /std:c++latest, который можно отменить, чтобы восстановить поведение C ++ 17 с помощью /Zc:char8_t- . In the future, it will be supported with /std:c++latest, which can be reverted to C++17 behavior via /Zc:char8_t-. Компилятор EDG, лежащий в основе IntelliSense, пока не поддерживает эту возможность, поэтому возникают ложные ошибки для 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

Метафункция std::type_identity и объект функции std::identity std::type_identity metafunction and std::identity function object

P0887R1 type_identity. P0887R1 type_identity. Устаревшее расширение класса шаблонов std::identity было удалено и заменено на метафункцию std::type_identity и объект функции std::identity в C++20. 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.

В следующем примере становится устаревшим предупреждение C4996 для std::identity (определено в ) в Visual Studio 2020: The following example produces deprecation warning C4996 for std::identity (defined in ) in Visual Studio 2020:

В следующем примере показано, как использовать новый std::identity (определено в ) вместе с новым std::type_identity : The following example shows how to use the new std::identity (defined in ) together with the new std::type_identity :

Проверка синтаксиса для универсальных лямбда-выражений 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 2020 этот код компилируется без предупреждений, но в Visual Studio 2020 возникает ошибка C2760 синтаксическая ошибка: непредвиденный токен » «, ожидается «id-expression» : In Visual Studio 2020, this code compiles without warnings, but in Visual Studio 2020 it produces error C2760 syntax error: unexpected token ‘ ‘, expected ‘id-expression’:

В следующем примере показан правильный синтаксис, который теперь применяется компилятором принудительно: The following example shows the correct syntax, now enforced by the compiler:

Зависящий от аргументов поиск вызовов функций 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)

  • starts_with() и ends_with() для basic_string и basic_string_view . starts_with() and ends_with() for basic_string and basic_string_view .
  • contains() для ассоциативных контейнеров; contains() for associative containers.
  • remove() , remove_if() и unique() для list и forward_list теперь возвращают size_type ; remove() , remove_if() , and unique() for list and forward_list now return size_type .
  • shift_left() и shift_right() добавлены к . shift_left() and shift_right() added to .

Улучшения соответствия C++ в 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 2020 версии 16.1 и более ранних версиях, но вызывает C2338 в Visual Studio 2020 версии 16.2: The following example compiles in Visual Studio 2020 version 16.1 and earlier, but produces C2338 in Visual Studio 2020 version 16.2:

Чтобы устранить эту ошибку, добавьте выражение noexcept в объявление функции: To fix the error, add the noexcept expression to the function declaration:

Двоичные выражения с различными типами перечисления 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 2020 версии 16.2 и более поздних в следующем примере кода создается предупреждение уровня 4, если включен параметр компилятора /std:c ++latest: In Visual Studio 2020 version 16.2 and later, the following code produces a level 4 warning when the /std:c++latest compiler option is enabled:

Чтобы избежать этого предупреждения, используйте static_cast для преобразования второго операнда: To avoid the warning, use static_cast to convert the second operand:

Двоичные выражения с типами перечисления и с плавающей запятой 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:

Чтобы избежать этого предупреждения, используйте static_cast для преобразования второго операнда: To avoid the warning, use static_cast to convert the second operand:

Равенство и реляционные сравнения массивов 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 2020 версии 16.2 следующий код создает C5056: оператор «==»: не рекомендуется для типов массивов, если включен параметр компилятора /std:c++latest: Starting in Visual Studio 2020 version 16.2, the following code produces C5056: operator ‘==’: deprecated for array types when the /std:c++latest compiler option is enabled:

Чтобы избежать этого предупреждения, можно сравнить адреса первых элементов: To avoid the warning, you can compare the addresses of the first elements:

Чтобы определить, равно ли содержимое двух массивов, используйте функцию std::equal: To determine whether the contents of two arrays are equal, use the std::equal function:

Результат определения оператора трехстороннего сравнения в == и != 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 2020 RTW и версии 16.1, но вызывает C2678 в Visual Studio 2020 версии 16.2: The following example compiles in Visual Studio 2020 RTW and version 16.1, but produces C2678 in Visual Studio 2020 version 16.2:

Чтобы избежать этой ошибки, определите оператор == или объявите его по умолчанию: To avo >

Улучшения стандартной библиотеки Standard Library improvements

  • to_chars() с фиксированной или научной точностью. to_chars() with fixed/scientific precision. (Общая точность в настоящее время запланирована на версию 16.4.) (General precision is currently planned for 16.4.)
  • P0020R6: atomic , atomic , atomic P0020R6: atomic , atomic , atomic
  • P0463R1: endian P0463R1: endian
  • P0482R6: Поддержка библиотек для char8_t P0482R6: Library Support For char8_t
  • P0600R1: [[nodiscard]] для STL, часть 1 P0600R1: [[nodiscard]] For The STL, Part 1
  • P0653R2: to_address() P0653R2: to_address()
  • P0754R2: P0754R2:

  • P0771R1: noexcept для конструктора перемещения std::function P0771R1: noexcept For std::function’s move constructor

Улучшения соответствия в Visual Studio 2020 версии 16.3 Conformance improvements in Visual Studio 2020 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[]: To avoid the error, use the extraction operator with a char[] variable:

Новые ключевые слова requires и concept New keywords requires and concept

В компилятор Microsoft C++ добавлены новые ключевые слова requires и concept. 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:

Чтобы избежать этой ошибки, объявите TotalDuration , как показано ниже: To avoid the error, declare TotalDuration as shown here:

Более строгая проверка функций 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 2020 версии 16.3 компилятор выполняет такую проверку. In Visual Studio 2020 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:

Чтобы избежать ошибок в предыдущем примере, используйте bool вместо BOOL в обоих объявлениях f . To avoid the errors in the previous example, use bool instead of BOOL consistently in both declarations of f .

Улучшения стандартной библиотеки Standard Library improvements

Нестандартные заголовки и h были удалены. The non-standard headers and have been removed. Код, который содержит их, должен включать стандартные заголовки и соответственно. Code that includes them should instead include the standard headers and , respectively.

Исправления ошибок и изменения в поведении в Visual Studio 2020 Bug fixes and behavior changes in Visual Studio 2020

Reinterpret_cast в функции constexpr Reinterpret_cast in a constexpr function

Reinterpret_cast запрещен в функции constexpr. A reinterpret_cast is illegal in a constexpr function. Компилятор Microsoft C++ раньше отклонял reinterpret_cast только в том случае, если он использовался в контексте constexpr. The Microsoft C++ compiler would previously reject reinterpret_cast only if it were used in a constexpr context. В Visual Studio 2020 во всех стандартных режимах языка компилятор правильно выполняет диагностику reinterpret_cast в определении функции constexpr. In Visual Studio 2020, 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.

Чтобы избежать этой ошибки, удалите модификатор constexpr из объявления функции. To avoid the error, remove the constexpr modifier from the function declaration.

Правильная диагностика для конструктора диапазонов basic_string Correct diagnostics for basic_string range constructor

В Visual Studio 2020 конструктор диапазонов basic_string больше не подавляет диагностику компилятора с помощью static_cast . In Visual Studio 2020, the basic_string range constructor no longer suppresses compiler diagnostics with static_cast . Приведенный ниже код компилируется без предупреждений в Visual Studio 2020, несмотря на возможную потерю данных при преобразовании из wchar_t в char при инициализации out : The following code compiles without warnings in Visual Studio 2020, despite the possible loss of data from wchar_t to char when initializing out :

Visual Studio 2020 корректно выдает предупреждение C4244: «argument»: преобразование из «wchar_t» в «const _Elem», возможна потеря данных. Visual Studio 2020 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:

Неправильные вызовы += и-= в /clr or /ZW теперь корректно обнаруживаются Incorrect calls to += and -= under /clr or /ZW are now correctly detected

В Visual Studio 2020 появилась ошибка, из-за которой компилятор пропускал ошибки без предупреждений и не создавал код для недопустимых вызовов += и –= в /clr или /ZW . A bug was introduced in Visual Studio 2020 that caused the compiler to silently ignore errors and generate no code for the inval >/clr or /ZW . Следующий код компилируется без ошибок в Visual Studio 2020, но в Visual Studio 2020 корректно вызывает ошибку C2845: ‘System::String ^’: расчеты с указателями недопустимы для этого типа: The following code compiles without errors in Visual Studio 2020 but in Visual Studio 2020 it correctly raises error C2845: ‘System::String ^’: pointer arithmetic not allowed on this type:

Чтобы избежать данной ошибки в этом примере, используйте оператор с методом 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

Доступ к недопустимым элементам в инициализаторах inline и static constexpr теперь определяется правильно. Invalid member accesses within inline and static constexpr initializers are now correctly detected. Следующий пример компилируется без ошибок в Visual Studio 2020, но в Visual Studio 2020 в режиме /std:c++17 он выдает ошибку C2248: не удается обратиться к закрытому элементу, объявленному в классе X. The following example compiles without error in Visual Studio 2020, but in Visual Studio 2020 under /std:c++17 mode it raises error C2248: cannot access private member declared in class ‘X’.

Чтобы избежать этой ошибки, объявите элемент X::c как защищенный: To avoid the error, declare the member X::c as protected:

Возобновлено использование C4800 C4800 reinstated

В MSVC ранее создавалось предупреждение о производительности C4800 для неявных преобразований в bool. MSVC used to have a performance warning C4800 about implicit conversion to bool. Это предупреждение было слишком назойливым и его нельзя было отключить, в результате чего мы решили удалить его в Visual Studio 2020. It was too noisy and could not be suppressed, leading us to remove it in Visual Studio 2020. Но за время работы Visual Studio 2020 мы получили множество отзывов о полезности этого предупреждения. However, over the lifecycle of Visual Studio 2020 we got lots of feedback on the useful cases it was solving. В выпуске Visual Studio 2020 мы возвращаем предупреждение C4800, тщательно настроив его и дополнив пояснительным предупреждением C4165. We bring back in Visual Studio 2020 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 — это по умолчанию отключенное предупреждение уровня 4, а C4165 — это по умолчанию отключенное предупреждение уровня 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.

В следующем примере возникают предупреждения C4800 и C4165 в режиме /Wall : The following example raises C4800 and C4165 under /Wall :

Чтобы избежать предупреждений в предыдущем примере, можно написать следующий код: To avoid the warnings in the previous example, you can write the code like this:

Функция-член локального класса не имеет тела Local class member function doesn’t have a body

В Visual Studio 2020 предупреждение C4822: функция-член локального класса не имеет тела возникает только тогда, когда параметр компилятора /w14822 явно не задан; он не отображается с /Wall . In Visual Studio 2020, 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 2020 C4822 является предупреждением, отключенным по умолчанию, которое можно обнаружить в /Wall без явного задания /w14822 . In Visual Studio 2020, C4822 is an off-by-default warning, which makes it discoverable under /Wall without having to set /w14822 explicitly.

Тела шаблонов функций, содержащие операторы 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 2020 следующий код вызывает предупреждение C7510: Type: имя зависимого типа должно дополняться префиксом «typename» только в том случае, если параметр /permissive- не задан. For example, in Visual Studio 2020 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 2020 тот же код вызывает ошибки независимо от того, задан ли параметр /permissive- : In Visual Studio 2020 the same code raises errors even when the /permissive- option is set:

Чтобы избежать этой ошибки, добавьте ключевое слово typename в объявление a : 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() .

В приведенном ниже коде возникает предупреждение C7552: встроенный ассемблер не поддерживается в лямбда-выражении в Visual Studio 2020 15.9 и Visual Studio 2020: The following code produces C7552: inline assembler is not supported in a lambda in both Visual Studio 2020 15.9 and in Visual Studio 2020:

Чтобы избежать этой ошибки, переместите код сборки в именованную функцию, как показано в следующем примере: To avoid the error, move the assembly code into a named function as shown in the following example:

Отладка перечислителя и std::move_iterator Iterator 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 ::iterator>, std::move_iterator ::iterator>, int*) теперь использует быстрый путь memcpy . For example, std::copy(std::move_iterator ::iterator>, std::move_iterator ::iterator>, int*) can now engage the memcpy fast path.

Исправления для принудительного применения ключевого слова Fixes for keyword enforcement

Применение ключевого слова в стиле макроса стандартной библиотеки было исправлено, чтобы выдавать ключевое слово фактически обнаруженной проблемы вместо сообщения общего характера. The standard library’s macro replacing a keyword enforcement 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 , std::allocator::size_type и std::allocator::difference_type теперь не считаются нерекомендуемыми. std::allocator , std::allocator::size_type , and std::allocator::difference_type are no longer deprecated.

Правильное предупреждение для сужающих преобразований строк Correct warning for narrowing string conversions

Лишний вызов static_cast , который не соответствовал стандарту и случайно отключал предупреждения о сужении C4244, был удален из std::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.»

Различные исправления правильности Various 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 сохраняет результат сбоя, а не создает исключение, если задан несуществующий целевой путь. The std::filesystem::directory_entry constructor now stores a failed result, rather than throwing an exception, when supplied a nonexistent target path.
  • Версия std::filesystem::create_directory с двумя параметрами была изменена для вызова версии с одним параметром, так как базовая функция CreateDirectoryExW использовала бы copy_symlink , если бы existing_p был символьной ссылкой. 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.
  • 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_relative больше не путается из-за конечных знаков косой черты, как сообщалось в LWG 3096. std::filesystem::path::lexically_relative is no longer confused by trailing slashes, reported as LWG 3096.
  • Найдено обходное решение для проблемы, при которой CreateSymbolicLinkW отклонял пути с символами косой черты в std::filesystem::create_symlink . Worked around CreateSymbolicLinkW rejecting paths with forward slashes in std::filesystem::create_symlink .
  • Найдено обходное решение проблемы, при которой функция delete режима удаления POSIX существовала в Windows 10 LTSB 1609, но фактически не могла удалять файлы. 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_searcher и std::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

Библиотека параллельных алгоритмов теперь правильно использует реальное семейство WaitOnAddress в Windows 8 и более поздних версий вместо того, чтобы всегда использовать Windows 7 и более ранние фиктивные версии. 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 std::linear_congruential_engine divide by zero

Некоторые условия, приводящие к тому, что std::linear_congruential_engine вызывает деление на ноль, были исправлены. Some conditions that would cause std::linear_congruential_engine to trigger divide by 0 have been fixed.

Исправления для распаковывания итератора Fixes for iterator unwrapping

Система распаковывания итератора, впервые предоставленная для интеграции пользователя и программиста в Visual Studio 2020 15.8 (как описано в записи блога STL Features and Fixes in VS 2020 15.8 (Функции STL и исправления ошибок в VS 2020 15.8), больше не распаковывает итераторы, производные от итераторов стандартных библиотек. The iterator unwrapping machinery that was first exposed for programmer-user integration in Visual Studio 2020 15.8, as described in C++ Team Blog article STL Features and Fixes in VS 2020 15.8, no longer unwraps iterators derived from standard library iterators. Например, пользователь, который происходит от std::vector ::iterator и пытается настроить поведение, теперь получает настроенное поведение при вызове алгоритмов стандартной библиотеки, а не поведение указателя. For example, a user that derives from std::vector ::iterator and tries to customize behavior now gets their customized behavior when calling standard library algorithms, rather than the behavior of a pointer.

Функция неупорядоченного контейнера reserve теперь действительно резервирует N элементов, как описано в LWG 2156. 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-дневного цикла (когда значение миллисекунд uint32_t принималось с переполнением в базовые API Win32). Now fixed, the overflows changed behavior on a seemingly random 29-day cycle (when uint32_t milliseconds accepted by underlying Win32 APIs overflowed).

Заголовок теперь правильно объявляет timespec и timespec_get в пространстве имен std , а не только в глобальном пространстве имен. The 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 , map и unordered_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 мы освобождаем граничный узел контейнера с помощью старого распределителя, выполняем назначение POCCA/POCMA в старом распределителе, а затем пробуем получить граничный узел из нового распределителя. 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. Если это распределение не удавалось, контейнер становился поврежденным и не мог даже быть уничтожен, поскольку обладание граничным узлом является инвариантной жесткой структурой данных. 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. Этот код был исправлен так, чтобы выделять новый граничный узел из распределителя исходного контейнера перед удалением существующего граничного узла. This code was fixed to allocate the new sentinel node from the source container’s allocator before destroying the existing sentinel node.

Контейнеры были исправлены и всегда копируют, перемещают или меняют распределители согласно propagate_on_container_copy_assignment , propagate_on_container_move_assignment и propagate_on_container_swap даже для распределителей, объявленных is_always_equal . 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 .

Добавлены перегрузки для функций-членов слияния и извлечения контейнеров, которые принимают контейнеры rvalue в соответствии с P0083 «Соединение карт и наборов» 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 2020 15.8 для операций чтения размером более 4 КБ. This change gives up some of the performance advantage that was gained in Visual Studio 2020 15.8 for reads larger than 4K in size. Но при этом сохраняется повышенная эффективность за счет избавления от трех виртуальных вызовов на каждый символ. However, efficiency improvements from avoiding three virtual calls per character are still present.

Конструктор std::bitset std::bitset constructor

Конструктор std::bitset теперь не считывает единицы и нули в обратном порядке для больших наборов битов. The std::bitset constructor no longer reads the ones and zeroes in reverse order for large bitsets.

Регрессия в std::pair::operator= std::pair::operator= regression

Исправлена регрессия в операторе присваивания std::pair , которая появилась при реализации LWG 2729 «Отсутствует SFINAE для std::pair::operator=». 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_t должен быть псевдонимом для typename add_const ::type , а не const T . In other words, add_const_t should be an alias for typename add_const ::type , not const T .

Исправления ошибок и изменения в поведении в версии 16.2 Bug fixes and behavior changes in 16.2

Константные блоки сравнения для ассоциативных контейнеров Const comparators for associative containers

Код для поиска и вставки в set, map, multiset и multimap был объединен для уменьшения размера кода. 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 2020 версии 16.1 и более ранних версиях, но вызывает C3848 в Visual Studio 2020 версии 16.2: The following code compiles in Visual Studio 2020 version 16.1 and earlier, but raises C3848 in Visual Studio 2020 version 16.2:

Чтобы избежать этой ошибки, используйте оператор сравнения const: To avoid the error, make the comparison operator const:


Улучшения соответствия в Visual Studio 2020 RTW (версия 15.0) Conformance improvements in Visual Studio 2020 RTW (version 15.0)

Благодаря поддержке обобщенного constexpr и NSDMI (нестатическая инициализация элементов данных) для статистических выражений компилятор Microsoft C++ в Visual Studio 2020 теперь включает все функции, добавленные в стандарте C++14. With support for generalized constexpr and non-static data member initialization (NSDMI) for aggregates, the Microsoft C++ compiler in Visual Studio 2020 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. Сведения о текущем состоянии компилятора см. в статье Соответствие стандартам языка Visual C++. See Visual C++ Language Conformance for a table that shows the current state of the compiler.

C++11 Поддержка выражения SFINAE в большем числе библиотек C++11: Expression SFINAE support in more libraries

Мы продолжаем улучшать в компиляторе Visual C++ поддержку SFINAE в выражениях. Это необходимо для определения и замены аргументов шаблонов, когда выражения decltype и constexpr могут выступать в качестве параметров шаблонов. 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. Дополнительные сведения см. в разделе Усовершенствования выражения SFINAE в версии-кандидате Visual Studio 2020. For more information, see Expression SFINAE improvements in Visual Studio 2020 RC.

C++14: NSDMI для статистических выражений C++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. Дополнительные сведения см. в разделе Инициализаторы членов и статистические выражения. For more information, see Member initializers and aggregates.

C++14: Расширенные constexpr C++14: Extended constexpr

Выражения, объявленные как constexpr, теперь могут содержать определенные виды объявлений, операторы if и switch, операторы циклов, а также изменения объектов, время существования которых началось с вычисления выражения 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 была неявной константой. Also, there is no longer a requirement that a constexpr non-static member function must be implicitly const. Дополнительные сведения см. в статье Нестрогие ограничения для функций constexpr. For more information, see Relaxing constraints on constexpr functions.

C++17 Сжатое static_assert C++17: Terse static_assert

Параметр сообщения для static_assert является необязательным. the message parameter for static_assert is optional. Дополнительные сведения см. в разделе Расширение 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. Дополнительные сведения см. в разделе Формулировка для атрибута [[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 и технической спецификации по диапазонам (которая уже готова, но еще не опубликована). 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. Дополнительные сведения см. в разделе Обобщение цикла 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. Дополнительные сведения см. в разделе Лямбда-выражения constexpr на C++. For more information, see constexpr lambda expressions in C++.

Операторы if constexpr в шаблонах функций if 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. Дополнительные сведения см. в статье Attributes in C++ (Атрибуты в 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. Дополнительные сведения см. в статье Attributes in C++ (Атрибуты в 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. Дополнительные сведения см. в разделе Правила конструкции значений класса перечисления и Перечисления. 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. Дополнительные сведения см. в документе о захвате объекта *this по значению в виде [=,*this] в лямбда-выражении. For more information, see Lambda Capture of *this by Value as [=,*this].

Удаление operator++ для bool 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 2020 версии 15.5 новый параметр компилятора /Zc:externConstexpr обеспечивает правильное поведение, соответствующее стандартам. In Visual Studio 2020 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_fn является заменой not1 и not2 . P0005R4 not_fn is a replacement of not1 and not2 .

Изменение формулировки для enable_shared_from_this Rewording enable_shared_from_this

P0033R1: класс enable_shared_from_this добавлен в C++11. 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 , shared_ptr shared_ptr , shared_ptr

P0414R2: внесение изменений shared_ptr из Library Fundamentals в C++17. 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 , возвращающую insert_return_type вложенного типа. 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

Нерекомендуемые функции в приложении D Annex D features deprecated

Приложение D стандарта C++ содержит все функции, признанные нерекомендуемыми, включая shared_ptr::unique() , и namespace std::tr1 . Annex D of the C++ standard contains all the features that have been deprecated, including shared_ptr::unique() , , 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. Дополнительные сведения см. в этой статье. For more information, see Standard library features in Annex D are marked as deprecated.

Пространство имен std::tr2::sys в теперь по умолчанию выдает предупреждение о нерекомендуемых функциях при использовании /std:c++14, а при использовании /std:c++17 оно по умолчанию удалено. The std::tr2::sys namespace in now emits a deprecation warning under /std:c++14 by default, and is now removed under /std:c++17 by default.

Улучшено соответствие в за счет отказа от нестандартного расширения (явных специализаций в классе). Improved conformance in by avoiding a non-standard extension (in-class explicit specializations).

Стандартная библиотека теперь использует шаблоны переменных внутренним образом. The standard library now uses variable templates internally.

Стандартная библиотека была обновлена в соответствии с изменениями компилятора C++17, включая добавление noexcept в систему типов и удаление спецификаций динамических исключений. 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. Основы работы с библиотеками V1 C++17 Library Fundamentals V1

P0220R1 включает технические спецификации основ библиотек для C++17 в стандарт. P0220R1 incorporates Library Fundamentals Technical Specification for C++17 into the standard. Содержит обновления для , , , , , , и . Covers updates to , , , , , , , and .

C++17 Улучшение выведения аргументов шаблонов класса для стандартной библиотеки C++17: Improving class template argument deduction for the standard library

P0739R0. Переместите adopt_lock_t в начало списка параметров, чтобы scoped_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 2020 версии 15.7 и более поздних в режиме /std:c++17 может оказаться недопустимым или иметь иную семантику код, который нормально работает в C++14 с использованием наследуемых конструкторов. In Visual Studio 2020 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:

В следующем примере показана реакция на событие /std:c++17 в Visual Studio 15.7: The following example shows /std:c++17 behavior in Visual Studio 15.7:

Дополнительные сведения см. в разделе Конструкторы. For more information, see Constructors.

C++17 Расширенная агрегатная инициализация C++17: Extended aggregate initialization

Если конструктор базового класса не является открытым, но доступен производному классу, то в режиме /std:c ++17 в Visual Studio версии 15.7 больше нельзя использовать пустые фигурные скобки для инициализации объекта производного типа. 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:

В 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 , и это работало успешно благодаря объявлению дружественных отношений. Previously, the Base private constructor was called via the Derived constructor, and it succeeded because of the friend declaration.

В следующем примере показано поведение C++17 в Visual Studio версии 15.7 в режиме /std:c++17: The following example shows C++17 behavior in Visual Studio version 15.7 in /std:c++17 mode:

C++17 Объявление параметров шаблона, не являющихся типами, с использованием auto C++17: Declaring non-type template parameters with auto

В режиме /std:c ++17 компилятор теперь может выводить тип аргумента шаблона, не являющегося типом и объявленного с auto: In /std:c++17 mode, the compiler can now deduce the type of a non-type template argument that is declared with auto:

В результате код 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. В следующем примере показан код C++14, который компилируется, поскольку вызов example(p) привязан к example(void*); . The following example shows C++14 code that compiles because the call to example(p) is bound to example(void*); . В Visual Studio 2020 версии 15.7 в режиме /std:c++17 шаблон функции example является оптимальным. In Visual Studio 2020 version 15.7, in /std:c++17 mode, the example function template is the best match.

В следующем примере показан код C++17 в Visual Studio 15.7 в режиме /std:c++17: The following example shows C++17 code in Visual Studio 15.7 in /std:c++17 mode:

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. Отказ от лишнего вырождения (частично) C++20: Avoiding unnecessary decay (partial)

P0777R1. Проводит различие между концепцией «вырождения» и простым удалением константы или квалификаторов ссылки. 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. В Visual Studio 2020 реализована поддержка remove_cvref_t . Support for remove_cvref_t is implemented in Visual Studio 2020.

C++17 Параллельные алгоритмы C++17: Parallel algorithms

P0024R2. Технические спецификации параллелизма включены в стандарт с небольшими изменениями. 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. Добавлены три новые перегрузки в std::hypot для типов float, double и long double, у каждой из которых есть три входных параметра. P0030R1 Adds three new overloads to std::hypot , for types float, double, and long double, each of which has three input parameters.

C++17: C++17:

P0218R1. Включает технические спецификации файловой системы в стандарт с некоторыми изменениями формулировок. P0218R1 Adopts the File System TS into the standard with a few wording modifications.

C++17 Специальные математические функции C++17: Mathematical special functions

P0226R1. Включает предыдущие технические спецификации для специальных математических функций в стандарт header. P0226R1 Adopts previous technical specifications for Mathematical Special Functions into the standard header.

C++17 Рекомендации по удержанию для стандартной библиотеки C++17: Deduction guides for the standard library

P0433R2. Обновляет до STL, чтобы воспользоваться преимуществами внедрения в C++17 P0091R3, который добавляет поддержку для выведения аргумента шаблона класса. 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 в новый заголовок и другие усовершенствования, включая изменение обработки ошибок для использования std::errc вместо std::error_code . P0682R1 Move the new elementary string conversion functions from P0067R5 into a new header and make other improvements, including changing error handling to use std::errc instead of std::error_code .

C++17: constexpr для char_traits (частично) C++17: constexpr for char_traits (partial)

P0426R1. Изменения в функциях-членах length , compare и find типа std::traits_type , позволяющие использовать std::string_view в константных выражениях. P0426R1 Changes to std::traits_type member functions length , compare , and find to make std::string_view usable in constant expressions. (В Visual Studio 2020 версии 15.6 поддерживается только для Clang/LLVM. (In Visual Studio 2020 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. Компилятор создает это предупреждение только в том случае, если указан режим /std:c++17 или более поздней версии, так как в 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. Если порядок вычисления должен быть слева направо, попробуйте передать операнды с использованием ссылки на константу. 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:

Исправления ошибок в Visual Studio 2020 RTW (версии 15.0) Bug fixes in Visual Studio 2020 RTW (version 15.0)

Инициализация копии списка Copy-list-initialization

Visual Studio 2020 правильно вызывает ошибки компилятора, связанные с созданием объектов с использованием списков инициализаторов, которые не обнаруживались в Visual Studio 2015 и могли приводить к сбоям или неопределенному поведению во время выполнения. Visual Studio 2020 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, при инициализации копии списка компилятор должен учитывать явный конструктор для разрешения перегрузки, но выдавать ошибку, если эта перегрузка выбирается на самом деле. 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 2020. The following two examples compile in Visual Studio 2015 but not in Visual Studio 2020.

Чтобы исправить эту ошибку, следует использовать прямую инициализацию: To correct the error, use direct initialization:

В Visual Studio 2015 компилятор ошибочно интерпретировал инициализацию копии списка так же, как обычную инициализацию копии. Он рассматривал только преобразование конструкторов для разрешения перегрузки. 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 2020 правильно выводит ошибку. In the following example, Visual Studio 2015 chooses MyInt(23) but Visual Studio 2020 correctly raises the error.

Этот пример аналогичен предыдущему, но выводит другую ошибку. This example is similar to the previous one but raises a different error. Он выполняется успешно в Visual Studio 2015, а в Visual Studio 2020 с C2668 завершается ошибкой. It succeeds in Visual Studio 2015 and fails in Visual Studio 2020 with C2668.

Нерекомендуемые определения типов Deprecated typedefs

Теперь Visual Studio 2020 выдает правильное предупреждение для нерекомендуемых определений типов, объявленных в классе или структуре. Visual Studio 2020 now issues the correct warning for deprecated typedefs that are declared in a class or struct. В следующем примере показана компиляция без предупреждений в Visual Studio 2015, но в Visual Studio 2020 выводится предупреждение C4996. The following example compiles without warnings in Visual Studio 2015 but produces C4996 in Visual Studio 2020.

constexpr constexpr

Visual Studio 2020 правильно выдает ошибку, если левый операнд в операции условного вычисления является недопустимым в контексте constexpr. Visual Studio 2020 correctly raises an error when the left-hand operand of a conditionally evaluating operation isn’t valid in a constexpr context. Следующий код компилируется в Visual Studio 2015, но не в Visual Studio 2020 (ошибка C3615: функция «f» с квалификатором constexpr не может выдавать константное выражение): The following code compiles in Visual Studio 2015 but not in Visual Studio 2020 (C3615 constexpr function ‘f’ cannot result in a constant expression):

Чтобы исправить эту ошибку, объявите функцию array::size() как constexpr или удалите квалификатор constexpr из f . To correct the error, either declare the array::size() function as constexpr or remove the constexpr qualifier from f .

Типы классов, передаваемые в функции с переменным числом аргументов Class types passed to variadic functions

В Visual Studio 2020 классы и структуры, передаваемые в функцию с переменным числом аргументов, например printf, должны быть доступны для простого копирования. In Visual Studio 2020, 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.

Чтобы исправить эту ошибку, можно вызвать функцию-член, возвращающую тип, доступный для простого копирования, To correct the error, you can call a member function that returns a trivially copyable type,

или выполнить статическое приведение для преобразования объекта перед его передачей: or else use a static cast to convert the object before passing it:

Для строк, созданных и управляемых с помощью 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.

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 2020: The following example compiles in Visual Studio 2015 but raises a compiler error in Visual Studio 2020:

Чтобы исправить эту ошибку, объявите 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 2020 выводится ошибка компилятора. In Visual Studio 2020, 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 2020: The following code compiles in Visual Studio 2015 but raises an error in Visual Studio 2020:

Отсутствующие списки аргументов шаблона 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 2020. The following code compiles in Visual Studio 2015, but produces an error in Visual Studio 2020.

Выражение 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:

Классы, объявляемые в анонимных пространствах имен 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 2020 это правило применяется частично. In Visual Studio 2020, the rule is partially enforced. Приведенный ниже пример кода вызывает в Visual Studio 2020 такую ошибку: «Ошибка C2201: const anonymous в пространстве имен ::S1::vftable: требуется внешняя ссылка для экспорта или импорта». The following example raises this error in Visual Studio 2020: «error C2201: const anonymous namespace::S1::vftable: must have external linkage in order to be exported/imported.»

Инициализаторы по умолчанию для членов класса значения (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. Инициализатор по умолчанию для класса значений всегда инициализирует члены нулевым значением. Default initialization of a value class always zero-initializes the members. Конструктор по умолчанию не допускается. A default constructor isn’t permitted. В Visual Studio 2020 инициализаторы членов по умолчанию вызывают ошибку компилятора, как показано в следующем примере: In Visual Studio 2020, default member initializers raise a compiler error, as shown in this example:

Индексаторы по умолчанию (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. Эту проблему удалось решить с использованием значения по умолчанию идентификатора для доступа к свойству. It was possible to work around the issue by using the identifier default to access the property. Возможное решение само по себе стало создавать проблемы после того, как значение по умолчанию было представлено как ключевое слово в C++ 11. The workaround itself became problematic after default was introduced as a keyword in C++11. В Visual Studio 2020 были исправлены ошибки, требующие обходного решения. Теперь компилятор выдает ошибку, когда значение по умолчанию используется для доступа к свойству по умолчанию для класса. In Visual Studio 2020, 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.

В Visual Studio 2020 оба свойства значения доступны по их именам: In Visual Studio 2020, you can access both Value properties by their name:

Исправления ошибок в 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 ::f (void)’: попытка ссылки на удаленную функцию»: The following code now produces C2280, «‘int S ::f (void)’: attempting to reference a deleted function»:

Чтобы устранить эту ошибку, объявите элемент i как int. To fix the error, declare i as int.

Проверки предварительных условий для признаков типов Pre-condition checks for type traits

В Visual Studio 2020 версии 15.3 улучшены проверки предварительных условий для признаков типов на более строгое следование стандарту. Visual Studio 2020 version 15.3 improves pre-condition checks for type-traits to more strictly follow the standard. Одна из проверок проверяет присвоение. One such check is for assignable. Для следующего кода создается ошибка C2139 в Visual Studio 2020 версии 15.3: The following code produces C2139 in Visual Studio 2020 version 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 2020 версии 15.3 следующий код вызовет предупреждение C4606: «‘A’: для передачи аргумента по значению через границу собственных и управляемых функций требуется допустимый конструктор копии. In Visual Studio 2020 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.

Чтобы устранить такую ошибку, удалите директиву #pragma managed , чтобы вызывающая функция стала собственной. Это позволит избежать маршалинга. To fix the error, remove the #pragma managed directive to mark the caller as native and avoid marshaling.

Экспериментальные предупреждения API для WinRT Experimental API warning for WinRT

API-интерфейсы WinRT, выпускаемые для экспериментов и обратной связи, обозначаются атрибутом Windows.Foundation.Metadata.ExperimentalAttribute . WinRT APIs that are released for experimentation and feedback are decorated with Windows.Foundation.Metadata.ExperimentalAttribute . В Visual Studio 2020 версии 15.3 при обнаружении этого атрибута компилятор выдает предупреждение C4698. In Visual Studio 2020 version 15.3, the compiler produces warning C4698 when it encounters the attribute. Некоторые API-интерфейсы в предыдущих версиях Windows SDK уже помечены этим атрибутом, поэтому обращения к этим 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»:

Чтобы отключить это предупреждение, добавьте атрибут #pragma. To disable the warning, add a #pragma:

Определение функции-члена шаблона вне строки Out-of-line definition of a template member function

Visual Studio 2020 версии 15.3 выводит сообщение об ошибке, если встречает внешние определения функций элемента шаблона, не объявленных в классе. Visual Studio 2020 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’:

Чтобы исправить такую ошибку, добавьте в класс следующее объявление: To fix the error, add a declaration to the class:

Попытка получить адрес указателя this Attempting to take the address of this pointer

В C++ указатель this является значением prvalue с типом указателя для X. Невозможно получить адрес 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 2020 версии 15.3 компилятор выдает ошибку C2664. In Visual Studio 2020 version 15.3, the compiler produces error C2664.

Преобразование в недоступный базовый класс Conversion to an inaccessible base class

Visual Studio 2020 версии 15.3 выводит сообщение об ошибке при попытке преобразовать тип в недоступный базовый класс. Visual Studio 2020 version 15.3 produces an error when you attempt to convert a type to a base class that is inaccessible. В компиляторе появляется «ошибка C2243: «приведение типа»: преобразование из «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:

Аргументы по умолчанию не допускаются во внешних определениях функций-членов 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 2020 версии 15.3 возникает предупреждение C5034, «A ::f»: внешнее определение члена шаблона класса не может иметь аргументы по умолчанию. Visual Studio 2020 version 15.3 produces warning C5034: ‘A ::f’: an out-of-line definition of a member of a class template cannot have default arguments:

Чтобы устранить такую ошибку, удалите аргумент по умолчанию = false . To fix the error, remove the = false default argument.

Использование offsetof с обозначением составного члена Use of offsetof with compound member designator

Если используется offsetof(T, m) , где m является «обозначением составного члена», Visual Studio 2020 версии 15.3 выдает предупреждение при компиляции с параметром /Wall. In Visual Studio 2020 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 2020 версии 15.3 выдает «предупреждение C4841: использовано нестандартное расширение — обозначение составного элемента в offsetof»: Visual Studio 2020 version 15.3 produces «warning C4841: non-standard extension used: compound member designator in offsetof»:

Чтобы исправить этот код, отключите предупреждение с помощью директивы pragma или уберите из кода offsetof . To fix the code, either disable the warning with a pragma or change the code to not use offsetof :

Использование offsetof со статическим элементом данных или функцией-членом Using offsetof with static data member or member function

Если используется offsetof(T, m) , где m ссылается на статические данные-член или на функцию-член, Visual Studio 2020 версии 15.3 выдает ошибку. In Visual Studio 2020 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'»:

Этот код является некорректным и может привести к сбою во время выполнения. 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 2020 версии 15.3 компилятор больше не игнорирует атрибуты, если __declspec(. ) применяется перед спецификацией компоновки extern «C» . In Visual Studio 2020 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»:

Чтобы устранить это предупреждение, переместите extern «C» вперед: To fix the warning, put extern «C» first:

В версии 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 2020 версии 15.3 следующий код вызывает сообщение «Ошибка C2280. ‘A ::

A(void)’: предпринята попытка ссылки на удаленную функцию». In Visual Studio 2020 version 15.3, the following code produces «error C2280: ‘A ::

A(void)’: attempting to reference a deleted function»:


Неинициализированные переменные const Uninitialized const variables

В выпуске Visual Studio 2020 RTW использовалась регрессия, из-за которой компилятор C++ не выдавал диагностических сообщений о том, что переменная const не инициализирована. Visual Studio 2020 RTW release had a regression in which the C++ compiler wouldn’t issue a diagnostic if a const variable wasn’t initialized. Эта регрессия была устранена в Visual Studio 2020 версии 15.3. This regression has been fixed in Visual Studio 2020 version 15.3. Следующий код теперь вызывает «Предупреждение C4132. ‘Value’: для константного объекта требуется инициализация». The following code now produces «warning C4132: ‘Value’: const object should be initialized»:

Чтобы исправить эту ошибку, присвойте значение переменной Value . To fix the error, assign a value to Value .

Пустые объявления Empty declarations

Теперь Visual Studio 2020 версии 15.3 предупреждает о пустых объявлениях для всех типов, а не только для встроенных. Visual Studio 2020 version 15.3 now warns on empty declarations for all types, not just built-in types. Теперь для следующего кода создаются предупреждения C4091 уровня 2 для всех четырех объявлений: The following code now produces a level 2 C4091 warning for all four declarations:

Чтобы устранить эти предупреждения, закомментируйте или удалите все пустые объявления. 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_convertible для типов массивов std::is_convertible for array types

В предыдущих версиях компилятора класс std::is_convertible выдавал неверные результаты для типов массива. Previous versions of the compiler gave incorrect results for std::is_convertible for array types. Из-за этого разработчикам библиотек необходимо было особым образом обрабатывать в компиляторе Microsoft C++ признаки типа std::is_convertible . This required library writers to special-case the Microsoft C++ compiler when using the std::is_convertible type trait. В следующем примере статические функции assert успешно срабатывают в предыдущих версиях Visual Studio, но в Visual Studio 2020 версии 15.3 завершаются ошибкой: In the following example, the static asserts pass in earlier versions of Visual Studio but fail in Visual Studio 2020 version 15.3:

std::is_convertible проверяет, правильно ли сформировано определение мнимой функции. std::is_convertible is calculated by checking to see if an imaginary function definition is well formed:

Частные деструкторы и std::is_constructible Private 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. В следующем примере статические функции assert успешно срабатывают в предыдущих версиях Visual Studio, но в Visual Studio 2020 версии 15.3 завершаются ошибкой: In the following example, the static asserts pass in earlier versions of Visual Studio but fail in Visual Studio 2020 version 15.3:

Закрытые деструкторы могут сделать тип неконструируемым. Private destructors cause a type to be non-constructible. При вычислении std::is_constructible подразумевается следующее объявление. std::is_constructible is calculated as if the following declaration were written:

Этот вызов подразумевает вызов деструктора. 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 2020 версии 15.3 корректно выдает ошибку C2668, неоднозначный вызов перегруженной функции «f»: In the following example, Visual Studio 2020 version 15.3 correctly raises C2668 ‘f’: ambiguous call to overloaded function:

Чтобы исправить код, удалите оператор using N::f , если вы намереваетесь вызвать ::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 2020 версии 15.3 корректно выдает ошибку C2660 (функция f не принимает 2 аргумента). In the following example, Visual Studio 2020 version 15.3 correctly raises C2660 ‘f’: function does not take two arguments:

Чтобы устранить эту проблему, измените сигнатуру 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 2020 версии 15.3 (с параметром /Wall) выдает «предупреждение C5038: данные-член ‘A::y’ будет инициализирован после данных-члена ‘A::x'»: In the following example, Visual Studio 2020 version 15.3 (with /Wall) raises «warning C5038: data member ‘A::y’ will be initialized after data member ‘A::x'»:

Чтобы устранить проблему, список инициализатора должен иметь тот же порядок, что и объявления. 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:

Проблема в приведенном выше примере заключается в том, что имеется два различия в типах (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.

Обработчики исключений 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. Он также больше не соответствует обработчику char* или wchar_t* в строковом литерале, если используется /Zc:strictstrings. It also no longer matches a handler of char* or wchar_t* to a string literal when /Zc:strictStrings is used.

Следующий код позволяет избежать этой ошибки: The following code avoids the error:

Пространство имен 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 2020 версии 15.5 приведенный ниже код вызывает предупреждение C4996: In Visual Studio 2020 version 15.5, the following code raises C4996:

Чтобы исправить ошибку, удалите ссылку на пространство имен tr1 . To fix the error, remove the reference to the tr1 namespace:

Функции стандартной библиотеки в приложении 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 2020 версии 15.5 приведенный ниже код вызывает предупреждение C4996: In Visual Studio 2020 version 15.5, the following code raises C4996:

Чтобы устранить ошибку, следуйте инструкциям в тексте предупреждения, как показано в следующем коде: To fix the error, follow the instructions in the warning text, as demonstrated in the following code:

Неиспользуемые локальные переменные 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:

Чтобы устранить ошибку, удалите неиспользуемую переменную. To fix the error, remove the unused variable.

Однострочные комментарии Single-line comments

В Visual Studio 2020 версии 15.5 компилятор C больше не создает предупреждения C4001 и C4179. In Visual Studio 2020 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. Эти предупреждения больше не нужны, так как однострочные комментарии входят в стандарт C, начиная с версии C99. The warnings are no longer needed because single-line comments have been part of the C standard since C99.

Если код не должен поддерживать обратную совместимость, вы можете избежать этих предупреждений, удалив подавление предупреждений C4001/C4179. 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.

Атрибуты __declspec с компоновкой extern «C» __declspec attributes with extern «C» linkage

В более ранних версиях Visual Studio компилятор игнорировал атрибуты __declspec(. ) , когда __declspec(. ) был применен перед спецификацией компоновки extern «C» . 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 2020 версии 15.5 предупреждение включено по умолчанию. In Visual Studio 2020 version 15.5, the warning is enabled by default.

Чтобы устранить ошибку, поместите спецификацию компоновки перед атрибутом __declspec: To fix the error, place the linkage specification before the __declspec attribute:

Это новое предупреждение C4768 выдается для некоторых заголовков Windows SDK, которые поставлялись с Visual Studio 2020 15.3 или более ранними версиями (например, с версией 10.0.15063.0, также известной как пакет SDK для RS2). This new warning C4768 is given on some Windows SDK headers that were shipped with Visual Studio 2020 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:

Переключитесь на последнюю версию Windows SDK, поставляемую вместе с выпуском Visual Studio 2020 версии 15.5. Switch to the latest Windows SDK that came with Visual Studio 2020 version 15.5 release.

Отключите предупреждение вокруг #include инструкции заголовка пакета Windows SDK: Turn off the warning around the #include of the Windows SDK header statement:

Компоновка 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 2020 версии 15.5 новый параметр компилятора ( /Zc:externConstexpr) обеспечивает корректное поведение, соответствующее стандартам. In Visual Studio 2020 version 15.5, a new compiler switch (/Zc:externConstexpr) enables correct standards-conforming behavior. В конечном счете это поведение будет использоваться по умолчанию. Eventually this behavior will become the default.

Если файл заголовка содержит переменную, объявленную как 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:

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 2020 версии 15.5 компилятор правильно выдает сообщение об ошибке: In Visual Studio 2020 version 15.5, the compiler correctly raises an error:

Тип целевого объекта 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:

Чтобы избежать этой ошибки, при использовании is_convertible следует сравнить типы указателей, поскольку сравнение типа, отличного от указателя, может завершиться неудачно, если один тип является абстрактным: 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:

Удаление спецификации динамических исключений и noexcept Dynamic exception specification removal and noexcept

В C++17 throw() является псевдонимом для noexcept, throw( ) и throw(. ) удалены, а определенные типы могут включать noexcept. In C++17, throw() is an alias for noexcept, throw( ) 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. Параметр /Zc:noexceptTypes- можно использовать для возврата к версии C++14 noexcept при использовании режима C++17 в целом. The /Zc:noexceptTypes- switch can be used to revert to the C++14 version of noexcept while using C++17 mode in general. Это позволяет обновить исходный код для соответствия C++17, не переписывая весь код throw() . 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.

Компилятор теперь также проверяет дополнительные спецификации несоответствующих исключений в объявлениях в режиме C++17 или с параметром /permissive- с новым предупреждением C5043. The compiler also now diagnoses more mismatched exception specifications in declarations in C++17 mode or with /permissive- with the new warning C5043.

Следующий код вызывает ошибки C5043 и C5040 в Visual Studio 2020 версии 15.5 при использовании параметра /std:c++17: The following code generates C5043 and C5040 in Visual Studio 2020 version 15.5 when the /std:c++17 switch is applied:

Чтобы исправить ошибки и продолжать использовать /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:

Встроенные переменные 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 2020 версии 15.5 указать параметр /std:c++17, следующий код теперь выдает предупреждение «C5041: size, невстроенное определение статических данных-члена constexpr не требуется и является нерекомендуемым в C++17«: In Visual Studio 2020 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:

Теперь предупреждение C4768 extern «C» __declspec(. ) включено по умолчанию extern «C» __declspec(. ) warning C4768 now on by default

Это предупреждение было добавлено в Visual Studio 2020 версии 15.3, но было отключено по умолчанию. The warning was added in Visual Studio 2020 version 15.3, but was off by default. В Visual Studio 2020 версии 15.5 предупреждение включено по умолчанию. In Visual Studio 2020 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.

Чтобы исправить этот код, удалите __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:

noexcept и частичные специализации noexcept and partial specializations

При наличии noexcept в системе типов частичные специализации для сопоставления отдельных «вызываемых» типов могут не пройти компиляцию или приводить к выбору основного шаблона из-за отсутствия частичной специализации для указателей на функции noexcept. 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, но при использовании /std:c++17 выдает ошибку C2027: «использование неопределенного типа ‘A ‘»: The following code compiles under /std:c++14 but fails under /std:c++17 with «error C2027:use of undefined type ‘A ‘»:

Следующий код успешно компилируется при указании параметра /std:c++17, так как компилятор выбирает новую частичную специализацию A : The following code succeeds under /std:c++17 because the compiler chooses the new partial specialization A :

Исправления ошибок и другие изменения в поведении в версии 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:

В Visual Studio 2020 версии 15.7 в режиме /std:c++17 аргумент по умолчанию не игнорируется: In /std:c++17 mode in Visual Studio 2020 version 15.7, the default argument isn’t ignored:

Разрешение имен зависимых объектов Dependent name resolution

Это изменение в поведении является обязательным условием для выведения аргумента шаблона для шаблонов класса — P0091R3. This behavior change is a precondition for Template argument deduction for class templates — P0091R3.

В следующем примере компилятор в Visual Studio 15.6 и более ранних версий разрешает D::type для B ::type в шаблоне основного класса. In the following example, the compiler in Visual Studio 15.6 and earlier resolves D::type to B ::type in the primary class template.

Visual Studio 2020 версии 15.7 в режиме /std:c++17 требует указать ключевое слово typename в инструкции using из D. Без typename компилятор вызывает предупреждение C4346: «B ::type»: зависимое имя не является типом, а также ошибку C2061, Синтаксическая ошибка: идентификатор type. Visual Studio 2020 version 15.7, in /std:c++17 mode, requires thetypename keyword in the using statement in D. Withouttypename, the compiler raises warning C4346: ‘B ::type’: dependent name is not a type and error C2061: syntax error: identifier ‘type’:

C++17. Атрибут [[nodiscard]] — повышение порога предупреждения C++17: [[nodiscard]] attribute — warning level increase

В Visual Studio 2020 версии 15.7 в режиме /std:c++17 порог предупреждения C4834 («отмена возвращаемого значения функции с атрибутом nodiscard») повышается с W3 до W1. In Visual Studio 2020 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

Список инициализации для базового класса конструктора шаблонов с переменным числом аргументов Variadic template constructor base class initialization list

В предыдущих версиях Visual Studio список инициализации для базового класса конструктора шаблонов с переменным числом аргументов мог не содержать аргументов шаблона (что недопустимо), и при этом не выдавалась ошибка. 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 2020 версии 15.7 компилятор выдает ошибку. In Visual Studio 2020 version 15.7, a compiler error is raised.

В следующем примере кода в Visual Studio 2020 версии 15.7 возникает Ошибка C2614. D : недопустимая инициализация члена. «B» не является базовым классом или членом. The following code example in Visual Studio 2020 version 15.7 raises error C2614: D : illegal member initialization: ‘B’ is not a base or member

Чтобы устранить ошибку, измените выражение B() на B (). To fix the error, change the B() expression to B ().

Агрегатная инициализация constexpr constexpr aggregate initialization

В предыдущих версиях компилятора C++ неправильно обрабатывалась агрегатная инициализация constexpr; принимался недопустимый код, в котором список агрегатной инициализации содержал слишком много элементов, и создавался неправильный объект 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:


В Visual Studio 2020 версии 15.7 с обновлением 3 и более поздних версий в предыдущий пример добавляется C2078 too many initializers. In Visual Studio 2020 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. При инициализации std::array , когда используются вложенные списки инициализации в скобках, укажите для внутреннего массива собственный вложенный список в скобках: When initializing a std::array with nested brace-init-lists, give the inner array a braced-list of its own:

Исправления ошибок и изменения в поведении в версии 15.8 Bug fixes and behavior changes in 15.8

Изменения компилятора в Visual Studio 2020 версии 15.8 входят в категорию исправления ошибок и изменений в поведении и перечислены ниже: The compiler changes in Visual Studio 2020 version 15.8 all fall under the category of bug fixes and behavior changes, and are listed below:

### Ключевое слово typename в неквалифицированных идентификаторах typename 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:

Чтобы исправить эту ошибку, измените вторую строку на 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, начиная с выпуска 2020 версии 15.6. The standard C++ attribute [[deprecated]] may be used instead, and is respected in Visual Studio 2020 version 15.6. Следующий код теперь вызывает ошибку C2760: синтаксическая ошибка: непредвиденный токен __declspec, ожидается type specifier. The following code now produces C2760 syntax error: unexpected token ‘__declspec’, expected ‘type specifier’:

Чтобы исправить эту ошибку, измените код на следующий (укажите атрибут перед знаком «=» определения псевдонима). To fix the error, change to code to the following (with the attribute placed before the ‘=’ of the alias definition):

Диагностика двухэтапного поиска имен Two-phase name lookup diagnostics

Для двухэтапного поиска имен нужно, чтобы независимые имена, используемые в тексте шаблона, отображались в шаблоне во время определения. 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:

Чтобы исправить эту ошибку, измените инструкцию return на return this->base_value; . To fix the error, change the return statement to return this->base_value; .

Примечание. В Python-библиотеке Boost в течение долгого времени существовало относящееся к MSVC обходное решение для опережающего объявления шаблона в unwind_type.hpp. 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. В режиме /permissive-, начиная с Visual Studio 2020 версии 15.8 (_MSC_VER=1915), компилятор MSVC корректно выполняет поиск в зависимости от аргументов (ADL) и согласуется с другими компиляторами, делая условие обходного решения ненужным. Under /permissive- mode starting with Visual Studio 2020 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, идентификатор не найден» , обновите файл заголовков по инструкции PR 229 из репозитория Boostorg. To avoid error C3861: ‘unwind_type’: identifier not found, see PR 229 in the Boost repo to update the header file. Мы уже исправили пакет Boost vcpkg, поэтому при получении или обновлении источника Boost из vcpkg не нужно применять отдельное исправление. 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.

В дальнейшем корпорация Майкрософт изменит место определения для некоторых типов стандартной библиотеки. 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: опережающее объявление vector в пространстве имен std запрещено стандартом C++ . The following code now raises C4643: Forward declaring ‘vector’ in namespace std is not permitted by the C++ Standard.

Чтобы исправить эту ошибку, используйте директиву include вместо опережающего объявления. To fix the error, use an include directive rather than a forward declaration:

Конструкторы, делегирующие самим себе Constructors that delegate to themselves

Стандарт C++ предполагает, что компилятор должен породить диагностическое сообщение, если делегирующий конструктор делегирует самому себе. The C++ standard suggests that a compiler should emit a diagnostic when a delegating constructor delegates to itself. Компилятор Microsoft C++ в режимах /std:c++17 и /std:c++latest теперь вызывает ошибку 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:

Чтобы избежать этого, делегируйте в другой конструктор. To avoid the infinite loop, delegate to a different constructor:

Постоянные выражения для offsetof offsetof with constant expressions

Макрос offsetof обычно реализовывался с помощью макроса, требующего reinterpret_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 2020 версии 15.8 компилятор ограничивает области, в которых можно использовать операторы reinterpret_cast в режиме по умолчанию, чтобы поведение кода лучше соответствовало стандарту C++. In Visual Studio 2020 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 на основе макроса в константных выражениях противоречит стандарту; используйте вместо этого offsetof, заданный в стандартной библиотеке C++» или «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.

Следующий код вызывает ошибку C4644 в режимах /default и /std:c++17, а также ошибку C2975 в режиме /permissive-: The following code raises C4644 in /default and /std:c++17 modes, and C2975 in /permissive- mode:

Чтобы исправить эту ошибку, используйте offsetof , определенный через . To fix the error, use offsetof as defined via :

Квалификаторы cv-qualifier в базовых классах, участвующих в раскрытии пакета cv-qualifiers on base classes subject to pack expansion

Компиляторы Microsoft C++ предыдущих версий не обнаруживали квалификаторы cv-qualifier в базовом классе, если он также участвовал в раскрытии пакета. 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 2020 версии 15.8 в режиме /permissive- следующий код вызывает ошибку C3770: const S: не является допустимым базовым классом. In Visual Studio 2020 version 15.8, in /permissive- mode the following code raises C3770 ‘const S’: is not a valid base class:

Ключевое слово 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 в инструкцию Base ::example (); , как показано в следующем примере: To fix the error, add the template keyword to the Base ::example (); statement, as shown in the following example:

Исправления ошибок и изменения в поведении в версии 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:

В Visual Studio 2020 версии 15.9 в режиме /permissive- выводится ошибка компилятора C3861: from_template: идентификатор не найден. In Visual Studio 2020 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 2020 версии 15.9 компилятор выводит ошибку C5050, если на сторонах создания и потребления используются несогласованные параметры командной строки для модулей. In Visual Studio 2020, 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.

В обоих случаях компилятор вызывает Предупреждение C5050. Возможная несовместимая среда при импорте модуля m: несоответствие версий C++. Несоответствие версий модуля — «201402» и «202003» . 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 «202003».

Компилятор также выдает ошибку C7536 при каждом изменении IFC-файла. 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. В следующем примере GCC и компилятор Microsoft C++ (в режиме /permissive-) выводят ошибку, тогда как Clang принимает код. In the following example, GCC and the Microsoft C++ compiler (in /permissive- mode) raise an error, while Clang accepts the code.

В предыдущем примере выводится ошибка C2668: The previous example raises C2668:

Расхождение реализаций связано с регрессией в формулировках стандарта 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. В следующем примере используется вспомогательный класс IsA , позволяющий удалять первую перегрузку, если Alloc является специализацией A : In the following example, we use a helper class IsA to remove the first overload when Alloc is a specialization of A :

Недопустимые выражения и типы, не являющиеся литералами, в определениях функций на основе шаблона 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:

В Visual Studio 2020 версии 15.9 этот код вызывает такую ошибку: In Visual Studio 2020 version 15.9, the code raises this error:

Чтобы избежать этой ошибки, удалите квалификатор constexpr из явного создания экземпляра функции f() . To avoid the error, remove the constexpr qualifier from the explicit instantiation of the function f() .

Улучшения соответствия стандарту C++ в Visual Studio 2015 C++ conformance improvements in Visual Studio 2015

Полный список улучшений соответствия вплоть до версии Visual Studio 2015 с обновлением 3 см. в разделе Visual C++ What’s New 2003 through 2015 (Новые возможности Visual C++ 2003–2015). For the complete list of conformance improvements up through Visual Studio 2015 Update 3, see Visual C++ What’s New 2003 through 2015.

[Перевод] Новинки С++17, которые необходимо использовать каждому 26.12.2020 11:35

Дамы и господа, здравствуйте.

Мы как раз закончили перевод интересной книги Яцека Галовица о STL С++ 17, которую надеемся выпустить чем раньше, тем лучше.

Сегодня же мы хотим предложить вашему вниманию перевод статьи Джулиана Темплмана с сайта «O’Reilly» с небольшим анонсом возможностей стандартной библиотеки нового стандарта С++.

Всех — с наступающим новым годом!

C++17 — крупный новый релиз, в нем более 100 новых возможностей и существенных изменений. Если говорить о крупных изменениях, то в новой версии не появилось ничего сравнимого по значимости со ссылками rvalue, которые мы получили в C++11, однако, есть масса изменений и дополнений, например, структурированные привязки и новые контейнерные типы. Более того, проделана большая работа, чтобы весь язык С++ стал более согласованным, разработчики постарались убрать из него бесполезные и ненужные поведения — например, поддержку триграфов и std::auto_ptr .

В этой статье мы обсудим два важнейших нововведения C++17, без которых разработчику совершенно не обойтись при создании современного кода на C++. Речь пойдет о структурированных привязках, обеспечивающих удобный новый способ работы со структурированными типами, а также о некоторых новых типах и контейнерах, которые добавились в Стандартную Библиотеку.

Структурированные привязки для множественного присваивания

Структурированные привязки — совершенно новый феномен, и при этом очень полезный. Они обеспечивают множественное присваивание от структурированных типов (например, кортежей, массивов и структур) — например, присваивание всех членов структуры отдельным переменным в единственной инструкции присваивания. Так код получается компактнее и понятнее.
Примеры кода со структурными привязками запускают на Linux при помощи коммпилятора clang++ версии 4 с флагом -std=c++1z , активирующим возможности C++17.

В C++11 появились кортежи, аналогичные массивам в том, что и те, и другие являются коллекциями фиксированной длины, но могут содержать смесь различных типов. При помощи кортежа можно вернуть от функции более одного значения, вот так:

Этот простой код возвращает кортеж с двумя элементами, и, начиная со стандарта C++14, можно использовать auto возвращаемыми типами этой функции, благодаря чему объявление этой функции получается гораздо чище, чем в противном случае. Вызывать функцию просто, но получение значений из кортежа может выглядеть довольно неаккуратно и нелогично, при этом может потребоваться std::get :

Также можно воспользоваться std::tie для привязки членов кортежа к переменным, которые сначала требуется объявить:

Однако, работая со структурированными привязками в C++17, можно связывать члены кортежей непосредственно с именованными переменными, и тогда необходимость в std::get отпадает, либо сначала объявлять переменные:

Работая таким образом, мы также можем получать ссылки на члены кортежа, а это было невозможно при применении std::tie . Здесь мы получаем ссылки на члены кортежа и, когда меняем значение одного из них, изменяется значение всего кортежа:

Вывод покажет, что значение t2 изменилось с 10 на 11.

Структурированные привязки для массивов и структур

Случай с кортежами наиболее очевиден, но структурированные привязки также можно использовать с массивами и структурами, например:

С массивами точно так же:

В этой реализации прослеживается пара недостатков:

Во-первых — и этот недостаток также актуален для std::tie — приходится привязывать все элементы. Поэтому невозможно, к примеру, извлечь из массива лишь первые четыре элемента. Если вы хотите частично извлечь cтруктуру или массив, то просто подставьте переменные-заглушки для тех членов, что вам не нужны, как показано в примере с массивом.
Во-вторых (и это разочарует программистов, привыкших использовать такую идею в функциональных языках, например, в Scala и Clojure), деструктуризация действует лишь на один уровень в глубину. Допустим, у меня в структуре Person есть член Location :

Можно сконструировать Person и Location , воспользовавшись вложенной инициализацией:

Можно предположить, что привязка в данном случае пригодится и для доступа к членам, но на практике оказывается, что такая операция недопустима:

Наконец, отмечу, что извлекать таким образом члены можно лишь из тех классов, в которых нужные вам данные являются общедоступными и нестатическими. Подробнее этот вопрос рассмотрен в следующей статье о структурированных привязках.

Новые библиотечные типы и контейнеры

В Стандартную Библиотеку в C++17 также добавилось множество новых и полезных типов данных, причем, некоторые из них зародились в Boost.
Код из этого раздела был протестирован в Visual Studio 2020.

Вероятно, самый простой тип std::byte — он представляет отдельный байт. Для представления байт разработчики традиционно пользовались char (знаковым или беззнаковым), но теперь есть тип, который может быть не только символом или целым числом; правда, байт можно преобразовывать в целое число и обратно. Тип std::byte предназначен для взаимодействия с хранилищем данных и не поддерживает арифметических операций, хотя, поддерживает побитовые операции.

Концепция «вариант» может показаться знакомой тем, кто имел дело с Visual Basic. Вариант — это типобезопасное объединение, которое в заданный момент времени содержит значение одного из альтернативных типов (причем, здесь не может быть ссылок, массивов или ‘void’ ).

Простой пример: допустим, есть некоторые данные, где возраст человека может быть представлен в виде целого числа или в виде строки с датой рождения. Можно представить такую информацию при помощи варианта, содержащего беззнаковое целое число или строку. Присваивая целое число переменной, мы задаем значение, а затем можем извлечь его при помощи std::get , вот так:

Если попытаться использовать член, который не задан таким образом, то программа выбросит исключение:

Зачем использовать std::variant , а не обычное объединение? В основном потому, что объединения присутствуют в языке прежде всего ради совместимости с C и не работают с объектами, не относящимися к POD-типам. Отсюда, в частности, следует, что в объединение не так-то просто поместить члены с копиями пользовательских конструкторов и деструкторов. С std::variant таких ограничений нет.

Другой тип, std::optional , удивительно полезен и на практике предоставляет возможности, существующие во многих функциональных языках. ‘optional’ — это объект, который может содержать либо не содержать значения; этот объект удобно использовать в качестве возвращаемого значения функции, когда она не может вернуть значение; тогда он служит альтернативой, например, нулевому указателю.

Работая с optional , мы приобретаем дополнительное преимущество: теперь возможность отказа функции явно обозначена прямо в объявлении, и, поскольку приходится извлекать значение из optional, значительно снижается вероятность, что мы случайно используем нулевое значение.

В следующем примере определяется функция преобразования, пытающаяся превратить строку в целое число. Возвращая optional , функция оставляет такую возможность: может быть передана недопустимая строка, преобразовать которую не удастся. Вызывающая сторона использует функцию value_or , чтобы получить значение из optional , а при отказе функции возвращает заданное по умолчанию значение, равное нулю (в случае, если преобразование не удалось).

Наконец, есть std::any , предоставляющий типобезопасный контейнер для одиночного значения любого типа (при условии, что оно обладает конструктором при копировании). Можно проверить, содержит ли any какое-либо значение, и извлечь это значение при помощи std::any_cast , вот так:

Можно воспользоваться членом type() , чтобы получить объект type_info , сообщающий, что содержится в any . Требуется точное соответствие между типами, в противном случае программа выбросит исключение std::bad_any_cast :

Когда может пригодиться такой тип данных? Простой ответ — во всех случаях, когда можно было бы воспользоваться указателем void* , но в данном случае гарантируется типобезопасность. Например, вам могут понадобиться разные представления базового значения: допустим, представить ‘5’ и в виде целого числа, и в виде строки. Подобные случаи распространены в интерпретируемых языках, но могут пригодиться и в случаях, когда требуется представление, которое не будет автоматически преобразовываться.

В этой статье рассмотрены лишь две новинки C++17, и я рекомендую любому специалисту по C++ также познакомиться и со всеми остальными новинками.

Важнейшие компиляторы, в том числе, GCC, Clang и MSVC, уже поддерживают многие из этих нововведений; подробнее об этом рассказано здесь.

В интернете есть несколько очень неплохих резюмирующих статей с описанием различных нововведений, появившихся в С++17, среди которых я бы особо отметил статью Тони ван Эрда, подробную статью на StackOverflow и отличную статью Бартека.

C++17: структурированные привязки, контейнеры и новые типы

9’159 подписчиков
2’797 просмотров на пост

Полезные материалы по всему, что может быть полезно плюсовику/сишнику.

Детальная рекламная статистика будет доступна после прохождения простой процедуры регистрации

  • Детальная аналитика 70’046 каналов
  • Доступ к 28’004’146 рекламных постов
  • Поиск по 112’332’059 постам
  • Отдача с каждой купленной рекламы
  • Графики динамики изменения показателей канала
  • Где и как размещался канал
  • Детальная статистика по подпискам и отпискам

Найдено 675 постов

Указатели — важная часть программирования на языках С и C++. Если вы читали, но ничего не поняли, советуем посмотреть данный туториал. Теперь вам всё станет ясно.

Иллюстративное введение в теорию графов и её применение

Не понимаете теорию графов? Эта статья для вас. Расскажем об основных элементах теории графов и рассмотрим применение теории.

Как получить индекс текущего элемента в современных циклах в C++.

Библиотека программиста
: 69515 | на пост: 14726 | ER: 21.2%
Публикации Упоминания Аналитика

Знакомы с принципом DRY? Если нет, следующая статья подробно опишет его основные положения и примеры применения.

Большой обзор удаленных и запрещенных функций в C++.

Обзор удобной библиотеки для форматирования строк на C++.

В этой статье автор объясняет, почему вы должны использовать std::for_each для прохождения цикла.

Об основах алгоритмов сортировки в иллюстрациях

Перевод простого гайда по алгоритмам сортировки, разобранным по винтикам и разложенным по полочкам!

Тони Гаддис является автором большого числа книг по Java и С++ и обучил не одно поколение программистов. Подход автора крайне прост — доступное и постепенное объяснение основ языка и его новых возможностей, однако профессионализм автора и язык повествования делают книгу незаменимым руководством по С++. Также книга содержит множество примеров по каждой теме и обновлённую главу по стандартной библиотеке шаблонов STL.

Библиотека для реализации криптографических алгоритмов.

Лучшие инструменты и советы начинающему C++ программисту

Хотите изучать C++? Делимся важными навыками, фреймворками и советами, которые помогут начинающему C++ программисту устроиться на работу.

Понимание работы с модулями.

Как спроектировать класс так, чтобы методы вызывались в определенном порядке? Хороший вопрос, и статья на него подробно отвечает.

Разбираем подробно работу указателей на класс.

Подробно про механизм try в C++.

На этом сайте вы найдете часто задаваемые вопросы по C++ на любой уровень.

Самые серьезные баги C++.

Разделяем данные с помощью итераторов в C++.

Большой список статей по стандартной библиотеке C++.

Мастер Йода рекомендует:  Pokemon Go — всё по этой теме для программистов

Добавить комментарий