casyup.me@outlook.com

0%

read/C++14C++17

C++14~C++17

之前我总结过 C++14 的一些东西, 但现在已经 2020 了啊 = =

所以就想着… emm… 虽然项目还是在用 C11 的东西, 连 C14 都没有. 但是! 需求不会留给你学习的时间的!(即使有, 但那对我不成立!) 所以就再看看 C17 的吧(虽然 C20 已经有了, 不过离实现和稳定还有一段时间, 有其他更优先的事情) 顺便对 C14 回顾一下 :happy:

(PS: 这次在下选择了 cppreference 作为参考)

C++14

原始链接

varaible template

这是一个让我感觉很迷的特性… 简单来说, 就是变量也可以像类和函数那样拥有模板, 例如

1
2
3
4
5
6
// declaration
template <typename T>
T n = T{};

// use
int i = n<int>;

查阅过一些信息, 比如在什么地方可以使用他.

一些测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void f() {
n<int> = 12;
}

int main() {
// 看起来怪怪的...
n<int> = 10;
cout << n<char> << endl;
cout << n<int> << endl;
{
n<int> = 11;
cout << n<int> << endl;
}
cout << n<int> << endl;
// @warning 变量模板的更改具有全局可见性
f();
cout << n<int> << endl;
}

// output
// A
// 10
// 11
// 11
// 12

我感觉可能离它远一点会比较好

测试结果来看. 它的原理类似于一个全局变量…(怎么感觉我在说废话 = =).

generic lambda

cppreference 是这么定义 lambda 的:

Constructs a closure: an unnamed function object capable of capturing variables in scope.

可以捕获作用域中变量的未命名函数对象.

关于 closure 的定义:

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.

一种具有第一类函数的实现词法作用域的名称绑定技术. 实现上, 闭合是一个将函数保存与环境一同保存的记录.

环境是一个当闭合被创建时将每个函数的自由变量(局部使用, 在封闭环境中定义)与被绑的名称的值/引用关联的映射.

与普通函数不同的是, 闭合允许函数通过闭合拷贝值/引用方位被捕获的变量. 即使当函数在它们(原来被捕获的变量)作用域外调用.

PS: 概念上来说, 和成员函数极其相似, 其具体实现也和类基本无二.

哦, 差点忘了, C14 说的是 generic lambda, 而非 lambda.

简单来说, 就是一个形似 auto. 实际实现为模板的 lambda.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// generic lambda, operator() is a template with two parameters
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14); // ok

// generic lambda, operator() is a template with one parameter
auto vglambda = [](auto printer) {
return [=](auto&&... ts) // generic lambda, ts is a parameter pack
{
printer(std::forward<decltype(ts)>(ts)...);
return [=] { printer(ts...); }; // nullary lambda (takes no parameters)
};
};
auto p = vglambda([](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; });
auto q = p(1, 'a', 3.14); // outputs 1a3.14
q(); // outputs 1a3.14

lambda init-capture

就是一个在捕获域里面可以初始化变量(变量自动 auto, 很让人不舒服的是, 我无法自行指定变量类型)的特性.

参考代码

relaxed restriction of constexpr

C14 扩展了 constexpr. 只要是基本能想到的, 编译器应该在编译期能做到的事情. 在 constexpr 里面都可以做.

比如简单的 if, switch… 参考

binary literals

直译过来就是二进制字面量. 可以参考

这让我很迷惑. 感觉就是 C11 的东西…

digit separators

这个挺好的, 属于代码规范的一种

1
2
3
4
unsigned long long l1 = 18446744073709550592ull; // C++11
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C++14
unsigned long long l3 = 1844'6744'0737'0955'0592uLL; // C++14
unsigned long long l4 = 184467'440737'0'95505'92LLU; // C++14

return type deducation for function

函数返回类型推导

1
2
3
4
5
6
7
8
9
decltype f() ->auto {
return ...
}
// 没记错的话大概是这个么结构(但应该是记错了, 不过没关系, 知道新的就好了)

// 新的方式明显简单直观. 没有那么八股文了
auto f() {
return ...
}

aggregate class with default non-static member initializers

就是一个对于纯成员变量, 无构造函数的构造优化. 具体参考

C++17

fold expression

用于变长模板的特性, 记住, 然后活用就好了. 规则

class template arugument deduction

类模板参数的推导. 可以更方便了.

1
2
3
4
vector<int> v{1};

// C++14
vector v{1};

non-type template parameters declared with autp

在模板中使用 auto 替代 typename. 既可以推导其类型, 又可以获取其值.

1
2
3
4
template <typename T, T v>
T v2 = v;
template <auto v>
auto v2 = v;

两者是等价的. 还有一些其他用途

compile timr if constexpr

一种 if 的编译时版本.

1
2
3
4
5
if constexpr (cond1) {
...
} else if constexpr () {
...
}

可以查看 参考

inline variables

内联变量.这个关键字声明的变量具有可以被多次包含的特性. 但同时也有一些规则. 最典型的应该是类静态成员的声明

1
2
3
4
5
6
7
8
9
class A {
static int i;
};
int A::i = 10;

// C++17
class A {
inline static int i = 10;
};

详细可以 参考1. 参考2

structured binding

一种绑定结构化数据的手段. 参考

initializers of if and switch

If 和 switch 可以有初始化区域了, 就如同 for 一样(while: ?? 那我呢?) 参考

u8 character literal

u8 字面量. 参考 感觉很没用, 程序代码就不该出现 unicode! (注释除外)

simplifield netesd namaspace

简化的嵌套作用域声明. 算是代码可读性的一种.

1
2
3
4
5
6
7
8
9
10
namespace A{
namespace B{
...
}
}

// C++17
namespace A::B {
...
}

unsing declaration declaring mutiple names

1
using A::g, A::g; // (C++17) OK: double declaration allowed at namespace scope

new order of evalution rules

一个有趣的东西 但我始终认为这类迷惑应该是需要避免的.

guaranteed copy elision

一种避免拷贝构造的特性. 参考

这个看起来是编译器做的优化. f() 本来是个无参函数. 但是在调用 f() 是却传了一个外部的地址(v的地址)过去

而其在使用的时候, 也做了相应调整.

lambda capture of *this

参考

可以捕获外部 this 的lambda. (感觉这群人对 lambda 很上心啊… 连续好几个强化了)

constexpr lambda

参考

实现了 constexpr 的lambda…

has include

参考

可以通过函数(大概率其实是一种告知编译器的宏) 这也是 C++ 一向的态度了. 换成其他语言, 根本不会将这种编译时相关信息抛给用户. 这是 C++ 的优势, 也是它复杂的根源之一.

atttribute namespace don’t have to repeat

刚说完又来了. 参考

引入具体实现的相关特性.