C++14 不是“新语言”,而是让 C++11 更好用的“打磨版本”
C++14 是 C++11 的一次增量式更新(ISO/IEC 14882:2014),于 2014 年正式发布。它没有引入革命性特性,而是对 C++11 的语法、模板、泛型编程和标准库进行打磨、简化与增强,目标是提升开发效率、代码可读性和表达力。
以下是对 C++14 新增特性的全面总结,包含详细说明与示例代码。
一、核心设计目标
- 简化泛型编程
- 减少样板代码(boilerplate)
- 增强
constexpr能力 - 改进 lambda 表达式
- 完善标准库工具
✅ C++14 被称为 “C++11 的 bug fix + 小幅增强版”。
二、语言核心新特性
1. 函数返回类型推导(Return Type Deduction for Functions)
允许普通函数使用 auto 自动推导返回类型(C++11 仅支持 lambda)。
auto add(int a, int b) {
return a + b; // 返回类型推导为 int
}
auto get_value() {
if (cond)
return 42; // int
else
return 3.14; // ❌ 错误!类型不一致
}
⚠️ 所有
return语句必须推导出相同类型(或可隐式转换为同一类型)。
2. 广义化的 constexpr 函数(Relaxed constexpr)
C++14 极大放宽了 constexpr 函数的限制:
|
C++11 限制 |
C++14 允许 |
|---|---|
|
只能有一条 |
✅ 多条语句、循环、分支 |
|
不能有局部变量(除 literal type) |
✅ 可声明局部变量 |
|
不能有 |
✅ 支持完整控制流 |
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
constexpr int f = factorial(5); // 编译期计算:120
✅ 现在 constexpr 函数几乎可以像普通函数一样写!
3. 变量模板(Variable Templates)
允许定义模板化的变量(而不仅是类型或函数)。
template<typename T>
constexpr T pi = T(3.1415926535897932385L);
// 使用
auto a = pi<float>; // 3.14159f
auto b = pi<double>; // 3.14159...
典型应用:类型特征简化
// C++11 需要 ::value
static_assert(std::is_const<int>::value == false, "...");
// C++14 引入变量模板(标准库已提供)
template<typename T>
constexpr bool is_const_v = std::is_const<T>::value;
static_assert(is_const_v<const int>, "..."); // 更简洁
📌 C++17 标准库广泛采用 _v(如 is_const_v)、_t(如 enable_if_t)后缀。
4. Lambda 表达式增强
(1) 泛型 Lambda(Generic Lambdas)
参数可用 auto,相当于隐式模板:
auto add = [](auto a, auto b) { return a + b; };
add(1, 2); // int + int
add(1.5, 2.5); // double + double
等价于:
struct __lambda {
template<typename T, typename U>
auto operator()(T a, U b) const { return a + b; }
};
(2) Lambda 捕获初始化(Init-Capture / Generalized Lambda Capture)
可在捕获列表中初始化新变量(包括移动捕获):
std::unique_ptr<int> p = std::make_unique<int>(42);
// 移动捕获(C++11 无法做到!)
auto lambda = [p = std::move(p)]() {
std::cout << *p << "\n";
};
// 初始化任意表达式
int x = 10;
auto f = [y = x + 1]() { return y; }; // y = 11
✅ 这是实现完美转发 lambda 和资源安全闭包的关键。
5. 二进制字面量与数字分隔符
(1) 二进制字面量
int flags = 0b1010'1100; // 二进制,值为 172
(2) 数字分隔符 '
提高大数字可读性(不影响值):
int million = 1'000'000;
double pi = 3.141'592'653'589;
✅ 分隔符可出现在数字任意位置(除开头/结尾)。
三、标准库增强
1. 共享互斥体(Shared Mutex) — <shared_mutex>
支持读写锁(Reader-Writer Lock):
#include <shared_mutex>
std::shared_timed_mutex mtx;
// 读操作(多个线程可同时读)
void read() {
std::shared_lock<std::shared_timed_mutex> lock(mtx);
// ... 读数据
}
// 写操作(独占)
void write() {
std::unique_lock<std::shared_timed_mutex> lock(mtx);
// ... 写数据
}
⚠️ C++14 提供
std::shared_timed_mutex,C++17 简化为std::shared_mutex。
2. std::make_unique(重大缺失补全!)
C++11 有 make_shared,但没有 make_unique,C++14 补上:
auto p = std::make_unique<MyClass>(arg1, arg2);
// 等价于:
// std::unique_ptr<MyClass> p(new MyClass(arg1, arg2));
// 但更安全(避免 new 与构造异常导致内存泄漏)
✅ 推荐总是使用
make_unique/make_shared,而非裸new。
3. 异构查找(Heterogeneous Lookup)
允许在 map/set 中使用不同类型键进行查找(需自定义比较器):
struct StringCompare {
using is_transparent = void; // 启用异构查找
bool operator()(const std::string& a, const std::string& b) const {
return a < b;
}
bool operator()(const char* a, const std::string& b) const {
return std::strcmp(a, b.c_str()) < 0;
}
// ... 其他重载
};
std::set<std::string, StringCompare> s = {"hello", "world"};
// 直接用字符串字面量查找,无需构造 string 临时对象!
if (s.find("hello") != s.end()) {
// ...
}
✅ 减少不必要的临时对象构造,提升性能。
4. 用户定义字面量(UDL)标准库扩展
C++14 为标准库添加了常用 UDL:
using namespace std::literals;
auto s = "hello"s; // std::string
auto t = 10ms; // std::chrono::milliseconds
auto d = 3.14h; // std::chrono::hours
auto c = 42i; // std::complex<double>{0, 42}
需要显式引入命名空间:
using namespace std::string_literals;
using namespace std::chrono_literals;
5. std::integral_constant 增强 & 类型操作
std::enable_if_t<Cond, T>(C++14)替代
typename std::enable_if<Cond, T>::typestd::decay_t<T>替代
typename std::decay<T>::typestd::remove_cv_t<T>等
_t别名大量引入
// C++11
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
foo(T x) { return x; }
// C++14
template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
foo(T x) { return x; }
✅ 代码更简洁,模板元编程更易读。
6. 其他实用工具
|
工具 |
说明 |
|---|---|
std::exchange |
原子地替换值并返回旧值: |
std::quoted |
用于 I/O 流的字符串引号处理: |
std::cbegin/cend |
获取 const_iterator 的便捷函数 |
// std::exchange 示例
std::unique_ptr<Resource> old = std::exchange(current_resource, std::make_unique<Resource>());
// old 持有旧资源,current_resource 已更新
四、弃用与移除(C++14)
std::gets(C 风格危险函数)被彻底移除
-
动态异常规范(
throw(...))继续被弃用(C++11 已弃用)
五、C++14 vs C++11 对比速查表
|
特性 |
C++11 |
C++14 |
|---|---|---|
auto
函数返回类型 |
❌ |
✅ |
|
泛型 Lambda ( |
❌ |
✅ |
|
Lambda 初始化捕获 |
❌ |
✅ |
constexpr
支持循环/局部变量 |
❌ |
✅ |
|
变量模板 |
❌ |
✅ |
std::make_unique |
❌ |
✅ |
|
二进制字面量 |
❌ |
✅ |
|
数字分隔符 |
❌ |
✅ |
_t
/ |
部分 |
广泛支持 |
|
异构查找 |
❌ |
✅(需自定义比较器) |
六、最佳实践建议
- 优先使用
auto推导函数返回类型(除非接口需显式类型)
- 用
make_unique替代new - 泛型 Lambda + 初始化捕获
简化回调与资源管理
- 利用
_t/_v别名提升模板代码可读性
- 在 map/set 查找中启用异构查找
避免临时对象
七、总结
C++14 不是“新语言”,而是让 C++11 更好用的“打磨版本”。
它填补了 C++11 的关键空白(如make_unique),简化了泛型和并发编程,并为 C++17 的进一步演进铺平道路。
如果你已经掌握 C++11,升级到 C++14 几乎没有学习成本,但收益显著。
更多推荐



所有评论(0)