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
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...);
}
}
// 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
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 ;
}
[[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.
}
// 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
}
C++ 要求函数和变量extern在程序中只有一个定义,对于使用限定符的函数,这一要求已经放宽了inline。内联函数可以在多个点定义,但它们的所有定义必须相同;从模板实例化的函数和变量也是如此。在 C++17 之前,没有非模板变量这样的东西,尽管不需要在单个翻译单元中定义它的情况下需要单个全局对象并不少见。
C++17 ofrece la posibilidad de declarar múltiples variables inicializadas desde una tupla o estructura:
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();
C++ permite declarar e inicializar una variable en la instrucción if, si dicha variable es evaluable como condición booleana, se entrará en la rama verdadera de la instrucción; pero esto no es posible cuando la variable no es evaluable como 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 permite separar la declaración de la variable y su evaluación en la instrucción 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";
}
Existe una notación científica en base-2 para valores numéricos en coma flotante en base hexadecimal: 0x3.ABCp-10. La mantisa se expresa en hexadecimal y el exponente en decimal interpretado con respecto a base 2. El menor valor de precisión simple expresable estándar IEEE-754 sería 0x1.0p-126.
Asignación dinámica de memoria para datos alineados.
C++11 añadió la posibilidad de especificar el alineamiento para objetos, peró no especificó ningún mecanismo para asignar memoria dinámica correctamente a estos objetos alineados, en C++17 se añaden sobrecargas a los operadores new y delete para especificar la alineación:
C++11 añadió los literales de cadenas de texto 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 añade los literales de caracter de texto 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
Especificación de excepciones como parte del tipo de la función.
语言特点:
模板和通用代码
模板类的模板参数推导。
技术文件
p0091r2
。假设我们有以下定义:
在 C++17 标准之前,必须按所示构造以下对象:
如果我们允许编译器推断模板类构造函数的参数,我们可以将上面的代码替换为:
用 . 声明非类型化模板参数
auto
。技术文件
p0127r1
。必须明确指定非类型化模板参数的类型,这会导致不必要的冗长并降低那些旨在接收任何类型的常量参数的模板的灵活性:
该示例用于
decltype
在x
将两个参数传递给S
. 理想情况下,您将修改声明S
,以便x
不需要类型:这是通过允许
auto
在模板参数列表中使用来实现的:允许对所有非类型模板参数进行持续评估。
技术文件
n4198
。在 C++17 之前,C++ 允许以下非类型化模板参数:
&X::y
或评估为空成员指针的常量表达式。从 C++17 开始,非类型化模板参数可以是:
std::nullptr_t
.允许
typename
在模板参数(模板模板)技术文件
n4051
必须使用
class
模板参数的类型:从 C++17 开始,您还可以:
折叠表达式1。
技术文件
n4295
。可折叠表达式将模板参数包折叠在二元可折叠运算符上。
折叠运算符是:
(... operador expresión)
称为op
一元左折叠。(expresión operador ...)
称为op
一元右折叠。左右的一元折叠称为一元折叠。在一元折叠中,表达式必须包含未扩展的参数包。
(expresión1 operador1 ... operador2 expresión2)
whereoperador1
和are 折叠运算符类型的表达式operador2
称为二元折叠。在二元折叠中,
operador1
andoperador2
必须是相同的折叠运算符和expresión1
orexpresión2
必须包含未展开的参数包,但不能同时包含两者。如果expresión2
它包含未扩展的参数包,则该表达式称为左二元折叠。如果expresión1
它包含未扩展的参数包,则该表达式称为二进制右折叠。实例化一个可折叠的表达式会产生:
((Expr1 operador Expr2) operador ...) operador ExprN
向左折叠。Expr1 operador (... operador (ExprN-1 operador ExprN))
向右一元折叠。(((Expr operador Expr1) operador Expr2) operador ...) operador ExprN
对于左二元折叠。Expr1 operador (... operador (ExprN-1 operador (ExprN operador Expr)))
对于二进制右折叠。在每种情况下:
operador
是折叠运算符N
是参数包扩展中的元素数。ExprX
通过实例化模式并用第 X 个元素替换每个数据包参数来生成。对于二进制可折叠表达式,
Expr
它是通过实例化不包含未展开参数包的表达式生成的:实例化模板时,
todos
我们会得到:auto
大括号之间的列表的新演绎规则。技术文件
n3922
在 C++17 中,
auto
涉及元素列表的推理的类型推理规则 ( ) 发生了变化。对于列表复制初始化:
auto
推断std::initializer_list
列表中的类型是否相同,否则将是编译错误。对于列表初始化:
auto
它将推断该元素的类型;在 C++17 之前,它std::initializer_list
从一个元素中推导出一个。auto
它不会推断,这将是编译器错误。例子:
if
持续的。技术文件
p0128r1
。A
if
在编译时评估其条件并且从构建中丢弃未使用的分支,这对于简化某些代码很有用:使用
if
常量,不需要空函数:拉姆达斯
Lambda 常量表达式
技术文件
n4487
。在 C++17 之前,禁止 lambda 或其实例(闭包)成为常量表达式的一部分;这个限制是不一致的(因为传统的仿函数没有)并且是不必要的:
*this
在 lambda 中捕获技术文件
p0018r3
。在非静态成员函数中声明的 Lambda
this
隐式或显式捕获以通过指针访问对象变量this
;出于这个原因,通过复制或引用捕获对象上下文是相同的:这会导致异步编程出现问题,因为它可能导致使用不再有效的内存指针:
能够捕获
*this
解决了这个问题。属性
C++11 中添加了属性,C++17 添加了新属性。
属性
[[fallthrough]]
,[[nodiscard]]
和[[unused]]
技术文件
p0068r0
。该属性
[[fallthrough]]
用作指令,该指令位于a 中[[fallthrough]]
的标记之前,其目的是标记执行将故意下降到下一个标记:case
switch
case
该属性
[[nodiscard]]
可用于类型或函数;如果已经这样标记并且代码中没有使用类型或函数返回,则会产生编译器警报:该属性
[[unused]]
标记了由于某种原因未使用的实体。如果编译器要使用警报标记此类实体,则如果使用该属性,它将不会这样做:该属性不会阻止编译器编译标记的实体,因此这两个函数都将被编译,但都不会被标记为警报。
命名空间和枚举属性
技术文件
n4266
。从 C++17 开始,允许使用属性标记命名空间和枚举。
句法
变量
inline
。技术文件
n4424
。C++ 要求函数和变量
extern
在程序中只有一个定义,对于使用限定符的函数,这一要求已经放宽了inline
。内联函数可以在多个点定义,但它们的所有定义必须相同;从模板实例化的函数和变量也是如此。在 C++17 之前,没有非模板变量这样的东西,尽管不需要在单个翻译单元中定义它的情况下需要单个全局对象并不少见。定义嵌套命名空间
技术文件
n4230
。A partir de C++17 este código:
Será equivalente a:
Extender
static_assert
.Documento técnico
n3928
.A partir de C++17 el segundo parámetro de
static_assert
es opcional:Retorno múltiple y control de flujo más claros.
Enlazados estructurados1
Documento técnico
p0217r2
.C++17 ofrece la posibilidad de declarar múltiples variables inicializadas desde una tupla o estructura:
Inicializador en instrucción
if
.Documento técnico
p0305r0
.C++ permite declarar e inicializar una variable en la instrucción
if
, si dicha variable es evaluable como condición booleana, se entrará en la rama verdadera de la instrucción; pero esto no es posible cuando la variable no es evaluable como booleana:C++17 permite separar la declaración de la variable y su evaluación en la instrucción
if
:Generalización del bucle
for
de rango.Documento técnico
p0184r0
.Permite que el tipo del iterador
begin
sea diferente al tipo del iteradorend
.Miscelánea
Literales hexadecimales de números en coma flotante
Documento técnico
p0245r1
.Existe una notación científica en base-2 para valores numéricos en coma flotante en base hexadecimal: 0x3.ABCp-10. La mantisa se expresa en hexadecimal y el exponente en decimal interpretado con respecto a base 2. El menor valor de precisión simple expresable estándar IEEE-754 sería
0x1.0p-126
.Asignación dinámica de memoria para datos alineados.
Documento técnico
p0035r1
.C++11 añadió la posibilidad de especificar el alineamiento para objetos, peró no especificó ningún mecanismo para asignar memoria dinámica correctamente a estos objetos alineados, en C++17 se añaden sobrecargas a los operadores
new
ydelete
para especificar la alineación:Elisión de copia garantizada.
Documento técnico
p0135r0
.En C++17 se garantiza que ciertas copias serán elididas, en particular: cuando el objeto a elidir es un valor temporal.
Refinamiento del orden de evaluación de expresiones para C++ idiomático.
Documento técnico
p0145r2
.Garantías de progreso para la especificación técnica de Paralelismo V2.
Documento técnico
p0299r0
.Literales de caracteres UTF8.
Documento técnico
n4267
.C++11 añadió los literales de cadenas de texto UTF:
C++17 añade los literales de caracter de texto UTF:
Especificación de excepciones como parte del tipo de la función.
Documento técnico
p0012r1
.La especificación de excepciones no forma parte del tipo de la función en estándares previos a C++17:
A partir de C++17 se generaría un error:
Verificación estática de cabeceras.
Documento técnico
p0061r1
.La instrucción
__has_include
permitirá comprobar si una cabecera está disponibleCorrecciones sobre conversiones de arreglos a punteros.
Documento técnico
n4261
.Correcciones sobre constructores heredados.
Documento técnico
p0136r1
.Novedades de STL
Tipos de datos
std::variant
Union de tipado seguro.Documento técnico
p0088r2
.std::optional
Objeto que puede contener un valor arbitrario, o tal vez no.Documento técnico
n4480
.std::any
Objeto que puede contener diferentes tipos.Documento técnico
n4480
.std::string_view
Referencia a cadenas de texto.Documento técnico
n4480
.std::shared_mutex
mutex compartido.Documento técnico
n4480
.Invoke
std::invoke
Objeto de llamada genérica.Documento técnico
n4169
.Puede llamar cualquier objeto llamable: puntero a función, función, función miembro... con una sintaxis unificada.
std::apply
Llama una función con una tupla con parámetros.Documento técnico
n4480
.Especificación técnica de Sistema de Archivos v1
Documento técnico
p0218r0
.[class.path]
[class.filesystem.error]
[class.file_status]
[class.directory_entry]
[class.directory_iterator]
y[class.recursive_directory_iterator]
[fs.ops.funcs]
Especificación técnica de Paralelismo v1
Documento técnico
n4071
.Especificación técnica de Fundamentos de Librería v1
Documento técnico
p0220r1
.[func.searchers]
y[alg.search]
.[pmr]
.std::sample
.