// vvvv <-- Antes de C++17 no se permite usar auto aqui.
template <auto T>
void funcion() { /* ... */ }
static int i = 0;
int main()
{
funcion<0>(); // Correcto, T sera de tipo int con valor 0
funcion<'Z'>(); // Correcto, T sera de tipo char con valor 'Z'
funcion<&i>(); // Correcto, T sera de tipo int * con valor 0x????????
funcion<3.14>(); /* Error, T deberia ser de tipo double,
pero double y float no se permiten como parametro no-tipo */
funcion<int>(); // Error, se esperaba un valor no un tipo.
return 0;
}
auto a{'a'}; // a es de tipo char, antes deducia std::initializer_list<char> de un elemento.
auto b{0xb}; // b es de tipo int, antes deducia std::initializer_list<int> de un elemento.
auto c{1.f}; // c es de tipo float, antes deducia std::initializer_list<float> de un elemento.
template <typename ... T>
struct derivado : base<T> ...
{
using base<T>::f ...;
};
derivado<int, double, char> d;
/* Equivale a:
using base<int>::f;
using base<double>::f;
using base<char>::f; */
Lambda 常量表达式。
如果 lambda 满足成为常量表达式的要求,则可以这样使用:
// vvvvvvvvv <-- No se puede usar constexpr aqui antes de C++17
constexpr auto cinco = [](){ return 5; };
int main(int argc, char **)
{
switch (argc)
{
// vvvvvvv <-- Valido de C++17 en adelante
case cinco(): /* ... */ break;
default: std::cout << /* ... */ break;
}
return 0;
}
struct objeto
{
void f()
{
// v <-- Captura this por referencia
auto a = [&]() { valor = 100 ; }; // Equivale a this->valor = 100;
// v <-- Captura this por copia
auto b = [=]() { valor = 200 ; }; // Equivale a this->valor = 200;
// vvvvv <-- Copia el objeto
auto c = [*this]() mutable { valor = 300 ; } // Equivale a this->valor = 300;
a(); // this->valor contiene 100
b(); // this->valor contiene 200
c(); /* this->valor no se modifica, contiene 200.
Se modifica el this->valor de una copia */
}
int valor;
};
属性[[fallthrough]]。
它告诉编译器 a 末尾没有语句是break故意的:caseswitch
switch (variable)
{
case 0:
// Hacer cosas...
case 1: // <-- ALarma! falta break!
// Hacer cosas...
[[fallthrough]];
case 2: // <-- Ok, la falta de break es intencionada.
// Hacer cosas...
break;
}
属性[[nodiscard]]。
向编译器指示不应丢弃数据类型或函数的返回。
// vvvvvvvvvvvvv <-- Se aconseja no descartar este dato
struct [[nodiscard]] informacion { /* ... */ };
struct datos { /* ... */ };
informacion obtener_informacion() { /* ... */ }
[[nodiscard]] datos obtener_datos() { /* ... */ }
// ^^^^^^^^^^^^^ <-- Se aconseja no descartar este retorno
int main()
{
obtener_informacion(); // Alarma! Se esta descartando un objeto de tipo informacion!
obtener_datos(); // Alarma! Se esta descartando el retorno de obtener_datos!
return 0;
}
std::map<int, int> mii;
// i y b declarados por separado:
std::map<int, int>::iterator i;
bool b;
// +---- Asigna el retorno->first a i y el retorno->second a b
// | Valido en C++17 y anterior.
// vvvvvvvvv
std::tie(i, b) = mii.insert({1, 2});
/* iterador e insertado declarados en la misma línea, su tipo se deduce
de retorno->first y retorno->second respectivamente. Asigna el
retorno->first iterador y el retorno->second a insertado.
valido solo a partir de C++17 */
auto [iterador, insertado] = mii.insert({3, 4});
// ^^^^^^^^^^^^^^^^^^^^^ <--- Emparejamiento estructurado
struct abc { int a, b, c; };
abc f1() { return {2, 3, 5}; }
std::tuple<std::string, float, abc, int> f2() { return {"Hola mundo", 3.14f, {1, 2, 3}, 4}; }
std::array<int, 5> f3() { return {0, 1, 2, 3, 4}; }
// Asigna retorno.a a x, retorno.b a y, retorno.c a z
auto [x, y, z] = f1();
// ^^^^^^^^^ <--- Emparejamiento estructurado
// Asigna 1r elemento de la tupla a str, segundo a pi, tercero a xyz y cuarto a v
auto [str, pi, xyz, v] = f2();
// ^^^^^^^^^^^^^^^^^ <--- Emparejamiento estructurado
// Asigna retorno[0] a p0, retorno[1] a p1...
auto [p0, p1, p2, p3, p4] = f3();
// ^^^^^^^^^^^^^^^^^^^^ <--- Emparejamiento estructurado
C++17 就是 C++!
它是 C++ 编程语言的第六次修订,之所以不叫 C++6,是因为修订不是按修订顺序编号,而是按国际标准化组织 (ISO)批准修订的年份编号。也称为编程语言方言)。
在 C++17 之前出现了什么?
这是对C++语言历史的简要总结:
C++17 增加了什么?
因此,C++17 只不过是 C++ 语言的一个修订版,这个修订版与之前的版本相比增加了什么?
模板对象中的参数推导。模板对象可以以与在模板函数中推断模板参数的方式类似的方式推断模板参数:
但是,这个推演与模板推演功能并不完全相同,因为它不支持部分推演。
非类型化模板参数中的类型推导。它可以用作
auto
模板参数,以便模板推断提供的非类型参数的基础类型:typename
在 templates-template 中允许。声明模板模板时,现在可以互换使用
折叠表达式。typename
或class
(以前不能):可以在可变参数模板中的参数包上应用某些运算符:
折叠运算符是:
花括号 (+
,,,,,,,,,,,,,,,,,,,,,,,,,,可以像这样部署:_ _ _ _ _ _ _ _ _ _ _ _-
_ _ _ _ _ _ _ _ _ _ _*
/
%
^
&
|
~
=
<
>
<<
>>
+=
-=
*=
/=
%=
^=
&=
|=
<<=
>>=
==
!=
<=
>=
&&
||
,
.*
->*
{}
)中的值的新推导规则。当大括号之间只有一个值时,它会被推导出为一个值,而不是一个列表:
将参数包展开为子句using
。具有如下基础对象:
以及一个派生自多个的对象
base
:我们可以将
Lambda 常量表达式。derivado
所有版本的base<T>::f(T)
with 子句纳入范围:如果 lambda 满足成为常量表达式的要求,则可以这样使用:
它可以
constexpr
从 lambda 声明中省略,因为如果它们满足要求,默认情况下它们将是常量表达式。*this
在 lambdas中捕获。在对象方法内声明的 lambda 中,泛型将 catch
属性this
作为指针:[[fallthrough]]
。它告诉编译器 a 末尾没有语句是
属性break
故意的:case
switch
[[nodiscard]]
。向编译器指示不应丢弃数据类型或函数的返回。
属性[[maybe_unused]]
。向编译器指示可能不会有意使用实体。
上面的代码不会显示未使用该函数
命名空间和枚举属性。debug
或未使用该值的警报valor
。可以在命名空间和枚举值上应用属性:
变量inline
。可以使变量表现得像函数一样
嵌套命名空间。inline
,也就是说,将变量的多个相同定义视为相同的定义。命名空间:
可以声明为
的简化static_assert
。不再强制向
异常规范。static_assert
.从 C++17 开始,如果函数的签名中没有子句
结构化匹配。throw
,则认为它不抛出异常。对于具有多个返回值的函数(返回
控制结构中的初始化程序。std::pair
、、和聚合)std::tuple
,std::array
可以分别获取每个返回值:可以在
if
和中声明和初始化变量switch
:for
广义范围循环。现在允许
begin
在范围内为end
不同类型。if
恒定条件。它可以添加
在制品……constexpr
到子句if
中。如果不满足常量条件的条件,则该条件内的代码将无法编译。添加更多的东西。