Каковы новые характеристики C ++ 17?

Перевод, основанный на вопросе Yakk SO на Английском языке.


Уже приняли все характеристики C ++ 17, так что мало вероятно, что он переносит важные изменения. Были сделаны сотни предложений для C ++ 17.

Какие из этих характеристик добавили в C ++ в C ++ 17?

9
задан 23.05.2017, 15:39
1 ответ

Характерные для языка:

Шаблоны и Характерный Код

Вывод аргумента шаблона для классов шаблон.

Технический документ p0091r2.

Давайте предполагать, что у нас есть следующие определения:

std::vector<int> vi1 = { 0, 1, 1, 2, 3, 5, 8 };
std::vector<int> vi2;
std::mutex m;
unique_lock<std::mutex> ul(m, std::defer_lock);

template<class Func> class Foo() { 
public: 
    Foo(Func f) : func(f) {} 
    void operator()(int i) { 
        os << "Calling with " << i << std::endl;
        f(i); 
    } 
private: 
    Func func; 
    std::mutex mtx;
};

Перед стандартом C ++ 17, следующие объекты должны строиться, как он появляется:

pair<int, double> p(2, 4.5);
auto t = make_tuple(4, 3, 2.5);
copy_n(vi1, 3, back_inserter(vi2));

// Virtualmente imposible pasar una lambda al constructor
// de una clase plantilla sin declarar la lambda
for_each(vi2.begin(), vi2.end(), Foo<???>([&](int i) { ...}));

lock_guard<std::mutex> lck(foo.mtx);
// Notacion del documento tecnico N4470
lock_guard<std::mutex, std::unique_lock<std::mutex>> lck2(foo.mtx, ul);

auto hasher = [](X const & x) -> size_t { /* ... */ };
unordered_map<X, int, decltype(hasher)> ximap(10, hasher);

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

pair p(2, 4.5);
tuple t(4, 3, 2.5);
copy_n(vi1, 3, back_insert_iterator(vi2));

// Ahora esto es facil, en lugar de virtualmente impossible
for_each(vi.begin(), vi.end(), Foo([&](int i) { ...}));

auto lck = lock_guard(foo.mtx);
lock_guard lck2(foo.mtx, ul);

// NOTA: la deducción de argumentos de plantilla deduce
// los argumentos no explícitos
unordered_map<X, int> ximap(10, [](X const & x) -> size_t { /* ... */ });

Объявлять аргументы шаблона не-типа с auto.

Технический документ p0127r1.

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

template <typename T, T v> struct S { }; // Definicion
S<decltype(x), x> s;                     // Instanciacion

Пример использует decltype чтобы получать тип x (постоянная величина во времени компиляции) перед тем, как перемещать оба параметра в S. Идеальное состояло бы в том, чтобы изменять заявление S так что тип x его не потребовали:

S<x> s; // Instanciacion deseada

Это получают позволяя использование auto в списке параметров шаблона:

template <auto v> struct S; // Deduce el tipo de v

Позволять постоянную оценку всех аргументов шаблона не-типа.

Технический документ n4198.

Перед C ++ 17, C ++ позволяет следующие параметры шаблона не-типа:

  • Любой Цельный или Перечисленный Тип, который был бы постоянным выражением.
  • Указатели, которые указывали бы на объекты в статической памяти, функциях с соединенный или постоянные выражения, которые были бы оценены как недействительный указатель.
  • Ссылки на объекты в статической памяти или функциях с соединенный.
  • Указатели в членов &X::y или постоянные выражения, которые были бы оценены как недействительный указатель - a-miembro.

Начиная с C ++ 17 параметры шаблона не типа могут быть:

  • Любой Цельный или Перечисленный Тип, который был бы постоянным выражением.
  • Указатели, которые указывали бы на полный объект в статической памяти, функции или недействительном указателе.
  • Ссылки на glvalue снабжая ссылками полный объект в статической памяти или функции.
  • Любое постоянное выражение указателя в члена.
  • std::nullptr_t.

Позволять typename в параметрах - шаблонах (сдержись сдержись)

Технический документ n4051

Обязательно использовать class для типа параметра - шаблона:

template<template<typename> class X> struct S; // class es requerido

Начиная с C ++ 17 также смогут:

template<template<typename> typename X> struct S; // Se puede usar class o typename

Выражения plegables1.

Технический документ n4295.

Складное выражение, сложи пакет параметров шаблона на бинарном складном операторе.

Складные операторы:

+  -  *  /  %  ^  &  |  ~  =  <  >  <<  >>
+=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=
==  !=  <=  >=  &&  ||  ,  .*  ->*
  • Выражение типа (... operador expresión) в котором op он - складной оператор знают как складка unario в левую сторону.
  • Выражение типа (expresión operador ...) в котором op он - складной оператор знают как складка unario в правую сторону.

Складки unarios с левой стороной и правой стороной известны как складки unarios. В складке unario, выражение должно содержать пакет параметров, не расширяя.

  • Выражение типа (expresión1 operador1 ... operador2 expresión2) в котором operador1 и operador2 они - складные операторы знают как бинарная складка.

В бинарной складке, operador1 и operador2 они должны быть тем же складным оператором и expresión1 или expresión2 они должны содержать пакет параметров, не расширяя не обоих больше. Если expresión2 он содержит пакет параметров, не расширяя, выражение известно как бинарная складка с левой стороной. Если expresión1 он содержит пакет параметров, не расширяя, выражение известно как бинарная складка с правой стороной.

instanciación складного выражения производит:

  • ((Expr1 operador Expr2) operador ...) operador ExprN для складок unarios в левую сторону.
  • Expr1 operador (... operador (ExprN-1 operador ExprN)) для складок unarios в правую сторону.
  • (((Expr operador Expr1) operador Expr2) operador ...) operador ExprN для бинарных складок в левую сторону.
  • Expr1 operador (... operador (ExprN-1 operador (ExprN operador Expr))) для бинарных складок в правую сторону.

В каждом случае:

  • operador он - складной оператор
  • N это число элементов в расширении пакета параметров.
  • ExprX произведен в instanciar главный файл и заменять каждый параметр пакета X-ésimo элемент.

Для складного бинарного выражения, Expr произведено в instanciar выражение, которое не содержит пакет параметров, не расширяя:

template<typename... Args>
bool todos(Args... args) { return (args && ...); }

bool b = todos(true, true, true, false);

В instanciar шаблон todos мы получили бы:

bool todos(bool e1, bool e2, bool e3, bool e4) { return ((e1 && e2) && e3) && e4; }

Новая процедура вывода для auto со списками между ключами.

Технический документ n3922

В C ++ 17 меняют процедуру вывода типов (auto) для выводов, в которые вмешиваются списки элементов.

Для инициализации из-за копии списка:

  • Вывод типа auto приди к заключению std::initializer_list если типы в списке идентичны, или в противоположном случае это будет ошибка компиляции.

Для инициализации из-за списка:

  • В списках с единственным элементом, auto он придет к заключению о типе этого элемента; заблаговременно в C ++ 17 приходил к заключению об одной std::initializer_list элемента.
  • В списках с более чем одним элементом, auto он не придет к заключению, это будет ошибка компиляции.

Пример:

auto a = { 1, 2 };   // deduce std::initializer_list<int> de dos elementos
auto b = { 3 };      // deduce std::initializer_list<int> de un elemento
auto c{ 3 };         // deduce int, antes deducia std::initializer_list<int> de un elemento

if постоянная величина.

Технический документ p0128r1.

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

void funcion()
{
    // Se requiere la funcion vacia para eliminar la recursion
}

template <class T> 
void funcion(T&& elemento)
{
    // Hacer cosas con el elemento
}

template <class T, class... Parametros>
void funcion(T&& cabeza, Parametros&&... cola)
{
    funcion(cabeza);
    funcion(cola...); // Finaliza la recursion cuando cola... es una lista vacia
}

С if постоянная величина, пустая функция не необходима:

template <class T> 
void funcion(T&& elemento)
{
    // Hacer cosas con el elemento
}

template <class T, class... Parametros>
void funcion(T&& cabeza, Parametros&&... cola)
{
    funcion(cabeza);
    constexpr if (sizeof...(cola))
    {
        // No se genera esta parte del codigo si cola... es una lista vacia
        funcion(cola...);
    }
}

Lambdas

Lambdas постоянное выражение

Технический документ n4487.

Перед C ++ 17 был запрещен, что lambda или Ваша инстанция (closure) составляла часть постоянного выражения; это ограничение было неосновательным (так как традиционные funtores не располагают ею) и ненужным:

// Este codigo es valido en C++17 pero incorrecto en estandares previos
constexpr auto L = [](int i) { return i; }; // Correcto en C++17

auto L2 = [] { return 0; };
constexpr int I = L2(); // Correcto en C++17

Захватывать *this в lambdas

Технический документ p0018r3.

lambdas, объявленные в функции член не статическая, захватывают this подразумеваемо или ясно чтобы соглашаться на переменные объекта через указатель this; в пользу этого мотива задержание контекста объекта из-за копии или из-за ссылки они равны:

struct S {
    int x ;

    void f() {
        // Ambas lambdas son identicas pese a que su captura sea diferente:
        auto a = [&]() { x = 42 ; } // El acceso a x se transforma en (*this).x = 42
        auto b = [=]() { x = 43 ; } // El acceso a x se transforma en (*this).x = 43
    }
};

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

class Tarea {
private:
    int valor ;
public:
    Tarea() : valor(42) {}
    std::future generar()
    { return std::async( [=]()->int{ return valor ; }); }
};

std::future foo()
{
    Tarea tmp ;
    // La closure asociada con el std::future devuelto
    // tiene un puntero this implicito.
    return tmp.generar();
    // El puntero this de la closure deja de ser valido
    // al finalizar la funcion, despues del return
}

int main()
{
    std::future f = foo();
    f.wait();
    // El valor del futuro no es valido porque
    // el objeto que lo genero ya ha sido destruido
    assert( 42 == f.get() );
    return 0 ;
}

Когда могут захватывать *this реши проблему.

Признаки

Признаки были добавлены в C ++ 11 и C ++ 17 добавляет новые признаки.

Признаки [[fallthrough]], [[nodiscard]] и [[unused]]

Технический документ p0068r0.

Признак [[fallthrough]] он используется как инструкция, инструкция [[fallthrough]] он кладется непосредственно перед этикетка case в одном switch и Ваша цель состоит в том, чтобы помечать, что выполнение упадет до предстоящей этикетки case умышленным способом:

switch (c) {
    case 'a':
        f(); // WARNING: falta break
    case 'b':
        g();
        [[fallthrough]]; // Correcto
    case 'c':
        h();
}

Признак [[nodiscard]] смоги быть использованным на типах или на функциях; если он был помечен так и тип или возврат функции не использован в коде, произведется тревога компиляции:

[[nodiscard]] int funcion();
void metodo() {
    funcion(); // WARNING: valor de retorno de una funcion nodiscard es descartado.
}

[[nodiscard]] struct S { ... };
S crear_S();

void funcion() {
    crear_S(); // WARNING: valor de retorno de un type nodiscard es descartado.
}

Признак [[unused]] пометь организацию, которая в пользу какого-то мотива не используется. Если составитель будет помечать вышеупомянутую организацию с тревогой, он это не сделает, если признак будет использованным:

// Una de las dos funciones no se usa dependiendo de UNA_CONDICION
static void funcion1() { ... }
static void funcion2() { ... } // warning: funcion2 no se usa

void iface() {
#ifdef UNA_CONDICION
    funcion1();
#else
    funcion2();
#endif
}

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

[[unused]] static void funcion1() { ... }
[[unused]] static void funcion2() { ... }

Признаки в областях имен и перечисленные

Технический документ n4266.

Начиная с C ++ 17 позволено помечать области имен и перечисленные с признаками.

Синтаксис

Переменные inline.

Технический документ n4424.

C ++ потребуй, что функции и переменные extern имейте exáctamente определение в программе, это требование расслабилось для функций посредством цензора inline. Функции inline могут определяться в нескольких точках, но все Ваши определения должны быть тем же самым; то же самое происходит для функций и переменных instanciadas с шаблонов. Перед C ++ 17 не существовал ничто похожее для переменных не шаблон pesea, в который не является странным нуждаться в глобальном и единственном объекте без того, чтобы этот должен был быть определенным в единственной единице перевода.

Определение укрытых областей имен

Технический документ n4230.

Начиная с C ++ 17 этот код:

namespace A::B::C // Error en estandares previos a C++17
{
// codigo
}

Он будет эквивалентным в:

namespace A
{
namespace B
{
namespace C
{
// codigo
}
}
}

Увеличивать static_assert.

Технический документ n3928.

Начиная с C ++ 17 второй параметр static_assert он опциональный:

static_assert ( true  != true ); // Correcto en C++17, incorrecto en estandares anteriores
static_assert ( false != false , "Falso debe ser falso" );

Многообразный возврат и контроль разгрузки больше просветов.

Соединенные estructurados1

Технический документ p0217r2.

C ++ 17 предлагает возможность объявлять многообразные переменные, инициализировавшие с tupla или структуры:

std::tuple<T1,T2,T3> crear_tupla(/*...*/) { /*...*/ return { a, b, c }; }
auto [ x, y, z ] = crear_tupla(); // x deduce tipo T1, y deduce tipo T2, z deduce tipo T3

// iterador deduce tipo typeof(mapa)::iterator, insertado deduce bool
const auto [iterador, insertado] = mapa.insert({"clave", valor});

struct S { int x; volatile double y; };
S f();
// x deduce const int, y deduce const volatile double
const auto [ x, y ] = f();

"Стартап" в инструкции if.

Технический документ p0305r0.

C ++ позволь объявлять и инициализировать переменную в инструкции if, если вышеупомянутая переменная будет evaluable как условие booleana, войдут в истинную ветвь инструкции; но это не является возможным, когда переменная не evaluable как booleana:

if (int no_multiplo_de_3 = x % 3)
{
std::cout << no_multiplo_de_3 << " no es multiplo de 3\n";
}

// Error! decltype(mapa)::iterator no es evaluable como condicion
if (auto iterador = mapa.find("clave"))
{ ... }

C ++ 17 позволяет отделять заявление переменной и Вашей оценки в инструкции if:

if (auto iterador = mapa.find("clave"); iterador != mapa.end())
{
    std::cout << "clave existe en el mapa\n";
}

// Combinado con enlazados estructurados
if (const auto [iterador, insertado] = mapa.insert({clave, valor}); insertado)
{
    std::cout << clave << " ha sido insertada en el mapa\n";
}

Обобщение цикла for ранга.

Технический документ p0184r0.

Позволь, что тип iterador begin отличайтесь в тип iterador end.

Смесь

Буквальные шестнадцатеричные чисел в плавающей запятой

Технический документ p0245r1.

Существует научная нотация в основании-2 для числовой стоимости в плавающей запятой в шестнадцатеричном основании: 0x3. ABCp-10. mantisa выражает в шестнадцатеричном и выразитель в десятичном интерпретированный относительно основания 2. Самая меньшая стоимость простой точности стандартный expresable IEEE-754 был бы 0x1.0p-126.

Динамическое ассигнование памяти для выровненных данных.

Технический документ p0035r1.

C ++ 11 добавил возможность определять выравнивание для объектов, peró он не определил никакого механизма, чтобы распределять динамическую память правильно в эти выровненные объекты, в C ++ 17 добавляются, что ты перегружаешь операторов new и delete чтобы определять выравнивание:

void* operator new(std::size_t size, std::align_val_t alignment);
void operator delete[](void* ptr, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment, std::size_t size) noexcept;

Элизия гарантированной копии.

Технический документ p0135r0.

В C ++ 17 гарантируют, что некие копии будут уничтожены, в особенности: когда объект, который нужно уничтожать, - временная стоимость.

Утонченность порядка оценки выражений для C ++ идиоматический.

Технический документ p0145r2.

Гарантии прогресса для технической спецификации Параллелизма V2.

Технический документ p0299r0.

Буквальные символов UTF8.

Технический документ n4267.

C ++ 11 добавил буквальных цепей текста UTF:

auto utf8     = u8"UTF8"; // Literal de cadena de texto codificado en UTF8
auto utf16    = u"UTF16"; // Literal de cadena de texto codificado en UTF16
auto utf32    = U"UTF32"; // Literal de cadena de texto codificado en UTF32

C ++ 17 добавляет буквальных характера текста UTF:

auto utf8     = u8'8'; // Literal de caracter codificado en UTF8
auto utf16    = u'F';  // Literal de caracter codificado en UTF16
auto utf32    = U'X';  // Literal de caracter codificado en UTF32

Спецификация таких исключений как часть типа функции.

Технический документ p0012r1.

Спецификация исключений не составляет часть типа функции в предварительных стандартах в C ++ 17:

void f_throw() throw(int) {}
void f_no_throw() {}

using void_throw = void() throw(int);
// Presuntamente un puntero a funcion void que puede lanzar excepciones
void_throw *p;

p = f_throw;    // Correcto
p = f_no_throw; // Correcto tambien!

Начиная с C ++ 17 произвел бы ошибку:

p = f_throw;    // Correcto
p = f_no_throw; // ERROR: No se puede convertir void() a void() throw(int)

Статическая проверка заголовков.

Технический документ p0061r1.

Инструкция __has_include он позволит подтверждать, доступен ли заголовок

#if __has_include(<optional>)
#  include <optional>
#  define EXISTE_OPTIONAL 1
#elif __has_include(<experimental/optional>)
#  include <experimental/optional>
#  define EXISTE_OPTIONAL 1
#  define EXPERIMENTAL_OPTIONAL 1
#else
#  define EXISTE_OPTIONAL 0
#endif

Исправления на превращениях договоренностей в указатели.

Технический документ n4261.

Исправления на полученных в наследство строителях.

Технический документ p0136r1.

Новизна STL

Типы данных

std::variant Союз tipado страховка.

Технический документ p0088r2.

std::optional Объект, который может содержать произвольную стоимость, или возможно не.

Технический документ n4480.

std::any Объект, который может содержать различные типы.

Технический документ n4480.

std::string_view Ссылка на цепи текста.

Технический документ n4480.

std::shared_mutex mutex имеемый.

Технический документ n4480.

Invoke

std::invoke Объект характерного вызова.

Технический документ n4169.

Смоги называть любой объект llamable: указатель в функцию, функцию, функцию член... с унифицированным синтаксисом.

std::apply Назови функцию с tupla с параметрами.

Технический документ n4480.

Техническая спецификация Системы Файлов v1

Технический документ p0218r0.

Техническая спецификация Параллелизма v1

Технический документ n4071.

Техническая спецификация Основ Книжного магазина v1

Технический документ p0220r1.

12
ответ дан 24.11.2019, 13:57
  • 1
    уже я приношу 3 попытки закончить читать и даже не могу... – rnrneverdies 01.07.2016, 00:55