The type of a non-typed template parameter must be specified explicitly, this causes unnecessary verbosity and reduces the flexibility of those templates that are intended to receive constant arguments of any type:
template <typename T, T v> struct S { }; // Definicion
S<decltype(x), x> s; // Instanciacion
The example uses decltypeto get the type of x(a compile-time constant) before passing both parameters to S. Ideally, you would modify the declaration Sso that the type of xis not required:
S<x> s; // Instanciacion deseada
This is achieved by allowing the use of autoin the template parameter list:
template <auto v> struct S; // Deduce el tipo de v
Allow constant evaluation of all non-type template arguments.
An expression of the type (... operador expresión)that opis a folding operator is known as a unary left fold.
An expression of the type (expresión operador ...)that opis a folding operator is known as a unary right fold.
Unary folds to the left and right are known as unary folds. In a unary fold, the expression must contain an unexpanded parameter pack.
An expression of the type (expresión1 operador1 ... operador2 expresión2)where operador1and operador2are folding operators is known as a binary fold.
In a binary fold, operador1and operador2must be the same folding operator and expresión1or expresión2must contain an unexpanded parameter packet but not both. If expresión2it contains an unexpanded parameter pack, the expression is known as a left binary fold. If expresión1it contains an unexpanded parameter pack, the expression is known as a binary right fold.
Instantiating a collapsible expression produces:
((Expr1 operador Expr2) operador ...) operador ExprNfor unary folds to the left.
Expr1 operador (... operador (ExprN-1 operador ExprN))for unary folds to the right.
In C++17, the type inference rules ( auto) for inferences involving lists of elements change.
For list copy initialization:
The type inference autoinfers std::initializer_listif the types in the list are identical or else it will be a compile error.
For list initialization:
In lists with only one element, it autowill infer the type of that element; prior to C++17 it deduced one std::initializer_listfrom an element.
On lists with more than one element, autoit won't infer, it will be a compiler error.
Example:
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
A ifwhose condition is evaluated at compile time and the untaken branch is discarded from the build, is useful for simplifying some code:
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
}
With ifconstant, the empty function is not necessary:
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...);
}
}
Before C++17 it was forbidden for a lambda or its instance (closure) to be part of a constant expression; this restriction was inconsistent (since traditional functors do not have it) and unnecessary:
// 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
Lambdas declared in a non-static member function thisimplicitly or explicitly capture to access object variables through the pointer this; for this reason the capture of the object context by copy or by reference are the same:
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
}
};
This causes problems in asynchronous programming as it can cause the use of pointers to memory that is no longer valid:
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 ;
}
Being able to capture *thissolves the problem.
attributes
Attributes were added in C++11 and C++17 adds new attributes .
The attribute [[fallthrough]]is used as an instruction, the instruction [[fallthrough]]is placed just before a tag casein a switchand its purpose is to mark that the execution will intentionally fall until the next tag :case
switch (c) {
case 'a':
f(); // WARNING: falta break
case 'b':
g();
[[fallthrough]]; // Correcto
case 'c':
h();
}
The attribute [[nodiscard]]can be used on types or on functions; if it has been marked like this and the type or function return is not used in the code, a compiler alarm will be generated:
[[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.
}
The attribute [[unused]]marks an entity that is not used for some reason. If the compiler were to mark such an entity with an alarm, it will not do so if the attribute is used:
// 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
}
This attribute does not prevent the compiler from compiling the marked entity, so both functions will be compiled but neither will be marked with an alarm.
C++ requires that functions and variables externhave exactly one definition in the program, this requirement has been relaxed for functions using the qualifier inline. Inline functions can be defined at multiple points, but all of their definitions must be the same; the same is true for functions and variables instantiated from templates. Before C++17 there was no such thing for non-template variables although it is not uncommon to need a single, global object without it having to be defined in a single translation unit.
C++17 offers the ability to declare multiple variables initialized from a tuple or structure:
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++ allows to declare and initialize a variable in the statement if, if said variable is evaluable as a boolean condition, the true branch of the statement will be entered; but this is not possible when the variable is not boolean-evaluable:
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 allows you to separate the declaration of the variable and its evaluation in the statement 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.
Language features:
Templates and Generic Code
Template argument deduction for template classes.
Technical document
p0091r2
.Suppose we have the following definitions:
Prior to the C++17 standard, the following objects must be constructed as shown:
If we allow the compiler to infer the arguments for the template class constructors, we can replace the above code with:
Declare non-typed template arguments with
auto
.Technical document
p0127r1
.The type of a non-typed template parameter must be specified explicitly, this causes unnecessary verbosity and reduces the flexibility of those templates that are intended to receive constant arguments of any type:
The example uses
decltype
to get the type ofx
(a compile-time constant) before passing both parameters toS
. Ideally, you would modify the declarationS
so that the type ofx
is not required:This is achieved by allowing the use of
auto
in the template parameter list:Allow constant evaluation of all non-type template arguments.
Technical document
n4198
.Before C++17, C++ allowed the following non-typed template parameters:
&X::y
or constant expressions that evaluate to null pointer-to-member.As of C++17 non-typed template parameters can be:
std::nullptr_t
.Allow
typename
in template-parameters (template template)Technical document
n4051
It is mandatory to use
class
for the type of a template-parameter:As of C++17 you can also:
Folding Expressions 1 .
Technical document
n4295
.A collapsible expression folds a template parameter packet over a binary collapsible operator.
The folding operators are:
(... operador expresión)
thatop
is a folding operator is known as a unary left fold.(expresión operador ...)
thatop
is a folding operator is known as a unary right fold.Unary folds to the left and right are known as unary folds. In a unary fold, the expression must contain an unexpanded parameter pack.
(expresión1 operador1 ... operador2 expresión2)
whereoperador1
andoperador2
are folding operators is known as a binary fold.In a binary fold,
operador1
andoperador2
must be the same folding operator andexpresión1
orexpresión2
must contain an unexpanded parameter packet but not both. Ifexpresión2
it contains an unexpanded parameter pack, the expression is known as a left binary fold. Ifexpresión1
it contains an unexpanded parameter pack, the expression is known as a binary right fold.Instantiating a collapsible expression produces:
((Expr1 operador Expr2) operador ...) operador ExprN
for unary folds to the left.Expr1 operador (... operador (ExprN-1 operador ExprN))
for unary folds to the right.(((Expr operador Expr1) operador Expr2) operador ...) operador ExprN
for left binary folds.Expr1 operador (... operador (ExprN-1 operador (ExprN operador Expr)))
for binary right folds.In each case:
operador
is the folding operatorN
is the number of elements in the parameter pack expansion.ExprX
is generated by instantiating the pattern and replacing each packet parameter with the Xth element.For a binary collapsible expression,
Expr
it is generated by instantiating the expression that does not contain an unexpanded parameter pack:When instantiating the template
todos
we would get:New rules of deduction for
auto
with lists between curly braces.Technical document
n3922
In C++17, the type inference rules (
auto
) for inferences involving lists of elements change.For list copy initialization:
auto
infersstd::initializer_list
if the types in the list are identical or else it will be a compile error.For list initialization:
auto
will infer the type of that element; prior to C++17 it deduced onestd::initializer_list
from an element.auto
it won't infer, it will be a compiler error.Example:
if
constant.Technical document
p0128r1
.A
if
whose condition is evaluated at compile time and the untaken branch is discarded from the build, is useful for simplifying some code:With
if
constant, the empty function is not necessary:lambdas
Lambdas constant expression
Technical document
n4487
.Before C++17 it was forbidden for a lambda or its instance (closure) to be part of a constant expression; this restriction was inconsistent (since traditional functors do not have it) and unnecessary:
Capture
*this
in lambdasTechnical document
p0018r3
.Lambdas declared in a non-static member function
this
implicitly or explicitly capture to access object variables through the pointerthis
; for this reason the capture of the object context by copy or by reference are the same:This causes problems in asynchronous programming as it can cause the use of pointers to memory that is no longer valid:
Being able to capture
*this
solves the problem.attributes
Attributes were added in C++11 and C++17 adds new attributes .
attributes
[[fallthrough]]
,[[nodiscard]]
and[[unused]]
Technical document
p0068r0
.The attribute
[[fallthrough]]
is used as an instruction, the instruction[[fallthrough]]
is placed just before a tagcase
in aswitch
and its purpose is to mark that the execution will intentionally fall until the next tag :case
The attribute
[[nodiscard]]
can be used on types or on functions; if it has been marked like this and the type or function return is not used in the code, a compiler alarm will be generated:The attribute
[[unused]]
marks an entity that is not used for some reason. If the compiler were to mark such an entity with an alarm, it will not do so if the attribute is used:This attribute does not prevent the compiler from compiling the marked entity, so both functions will be compiled but neither will be marked with an alarm.
Namespaced and Enumerated Attributes
Technical document
n4266
.As of C++17 it is allowed to mark namespaces and enums with attributes.
Syntax
Variables
inline
.Technical document
n4424
.C++ requires that functions and variables
extern
have exactly one definition in the program, this requirement has been relaxed for functions using the qualifierinline
. Inline functions can be defined at multiple points, but all of their definitions must be the same; the same is true for functions and variables instantiated from templates. Before C++17 there was no such thing for non-template variables although it is not uncommon to need a single, global object without it having to be defined in a single translation unit.Defining nested namespaces
Technical document
n4230
.As of C++17 this code:
It will be equivalent to:
extend
static_assert
.Technical document
n3928
.As of C++17 the second parameter of
static_assert
is optional:Multiple return and clearer flow control.
Structured Links 1
Technical document
p0217r2
.C++17 offers the ability to declare multiple variables initialized from a tuple or structure:
Initializer in instruction
if
.Technical document
p0305r0
.C++ allows to declare and initialize a variable in the statement
if
, if said variable is evaluable as a boolean condition, the true branch of the statement will be entered; but this is not possible when the variable is not boolean-evaluable:C++17 allows you to separate the declaration of the variable and its evaluation in the statement
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
.