🍎 C++14 特性

C++14 被称为“C++11 的修正版”,不追求大改动,但把 C++11 的很多用法变得更顺手、更实用。

Lambda 支持 auto 参数(泛型 lambda)

auto add = [](auto a, auto b) {
    return a + b;
};

让 lambda 变成真正的泛型函数对象。

Lambda 返回类型自动推导

auto f = [](int x) { return x * 2; };

不再需要写 -> int。

Lambda 捕获初始化(init capture)

auto p = std::make_unique<int>(10);
auto l = [q = std::move(p)] {
    // 使用 q
};

普通函数返回类型推导

auto add(int a, int b) {
    return a + b;
}

与 lambda 风格统一。

decltype(auto)

decltype(auto) f(auto&& x) {
    return std::forward<decltype(x)>(x);
}

精确保留返回值的引用/值属性,常用于完美转发。

变量模板(Variable Templates)

template<typename T>
constexpr T pi = T(3.141592653589793);

double d = pi<double>;

模板常量更自然。

二进制字面量 与 数字分隔符

int a = 0b101010;      // 二进制
int b = 1'000'000;    // 分隔符

读写更直观。

constexpr 函数中的更多功能

C++14 允许在 constexpr 函数中:

constexpr int fact(int n) {
    int r = 1;
    for (int i = 1; i <= n; ++i) r *= i;
    return r;
}

让编译期计算更实用。

放宽 constexpr 对构造/析构限制

用户自定义类型更容易成为字面量类型。

小修小补

std::make_unique

auto p = std::make_unique<Foo>(1, 2);

C++11 只有 make_shared,C++14 补齐,避免裸 new。

std::exchange

int old = std::exchange(x, 0);

常用于移动语义、状态切换。

共享锁 <shared_mutex>

读多写少场景更高效。

时间字面量 <chrono>

using namespace std::chrono_literals;
auto t = 100ms;

时间表达更自然。

tuple、type_traits、algorithm 增强

std::tuple_size_v

std::enable_if_t

多个 _t / _v 简化别名(部分在 C++14)

少写 ::type、::value

std::integer_sequence

std::index_sequence 和相关功能

std::make_index_sequence<N>

模板元编程展开参数包神器。

std::quoted

std::cout << std::quoted(str);

方便输出带引号字符串。

<complex><random><algorithm> 等修订

主要是修复和小增强。

变量模板

根据不同的类型去定义一个变量有哪些方法。

#include <iostream>
using namespace std;

template <class T>
struct PI
{
    static constexpr T value = static_cast<T>(3.1415926);
};

int main(int argc, char **argv)
{
    std::cout << PI<float>::value << std::endl; // 3.14159
    return 0;
}
#include <iostream>
using namespace std;

template <class T>
constexpr T PI()
{
    return static_cast<T>(3.1415926);
};

int main(int argc, char **argv)
{
    std::cout << PI<int>() << std::endl; // 3
    return 0;
}

C++14标准引入了变量模板的特性。

#include <iostream>
using namespace std;

template <class T>
constexpr T PI = static_cast<T>(3.1415926L);

int main(int argc, char **argv)
{
    std::cout << PI<float> << std::endl; // 3.1415926
    std::cout << PI<int> << std::endl;   // 3
    return 0;
}

变量模板的模板参数也可以是非类型的

#include <iostream>
using namespace std;

template <class T, int N>
T PI = static_cast<T>(3.1415926L) * N;

int main(int argc, char **argv)
{
    PI<float, 2> *= 5;
    std::cout << PI<float, 2> << std::endl; // 31.4159
    return 0;
}

有了变量模板,有一个好处就是用于模板元编程,如比较两个类型是否相同时会用到

bool b = std::is_same<int,std::size_t>::value;

但是::value有些鸡肋,可以用变量模板

template<class T1, class T2>
constexpr bool is_same_v = std::is_same<T1, T2>::value;

bool b = is_same_v<int, std::size_t>;

不过C++14标准库并没有is_same_v,知道C++17标准库的type_traits中对类型特征采用了变量模板,比如 some_trait<T>::value会增加与它等效的变量模板some_trait_v<T>