c++14特性
C++14特性
二进制字面值
二进制字面量提供了一种表示二进制数的便捷方式。可以用 '
分隔数字。
0b110
0b1111'1111
泛型 lambda 表达式
允许在参数列表中使用 auto
类型说明符,从而实现多态 lambda
auto identity = [](auto x) { return x; };
int three = identity(3); // == 3
std::string foo = identity("foo"); // == "foo"
Lambda 捕获初始化器
这个特性允许你在捕获变量时同时初始化它们,可以为捕获的变量指定初始值,而不必在外部定义或修改它们
[!note]
初始化表达式在 lambda 创建时(而不是调用时)进行求值
#include <iostream>
int main() {
int x = 10;
int y = 20;
// 使用捕获初始化器来指定捕获变量的初始值
auto lambda = [ x, y = y + 5]() mutable {
std::cout << "Captured x: " << x << ", y: " << ++y << std::endl;
};
// 打印捕获的变量
lambda(); //Captured x: 10, y: 26
x = 30;
y = 40;
lambda(); //Captured x: 10, y: 27
auto labmda_ref = [&a = x, y = y + 1]() mutable {
std::cout << "Captured a: " << a << ", y: " << y << std::endl;
};
labmda_ref(); //Captured a: 30, y: 41
return 0;
}
[ x, y = y + 5]
: 捕获了变量x
的值,并在捕获时将y
初始化为y+1
的结果[&a = x, y = y + 1]
: 通过引用捕获了x
,且可以设置与被引用变量不同的名称- 在捕获初始化器中创建的变量是属于Lambda内部的局部变量,不影响外部同名的变量
当前可以通过移动捕获的方式捕获移动类型
#include <memory>
#include <iostream>
int main() {
auto p = std::make_unique<int>(1);
auto lambda = [p = std::move(p)]() mutable {
*p = 5;
return std::move(p);
};
p = lambda();
std::cout << *p << std::endl;
return 0;
}
注意:
p
是通过移动捕获传递给Lambda的,移动之后,原来的p
变为空指针(nullptr
)- lambda捕获的变量默认是不可更改的,使用
mutable
以支持更改
返回类型推导
使用 auto
返回类型,编译器将尝试为您推导类型。对于 lambda 表达式,可以使用 auto
推导其返回类型
//return type as `int`
auto f(int i){
return i;
}
template <typename T>
auto& f(T& t) {
return t;
}
// Returns a reference to a deduced type.
auto g = [](auto& x) -> auto& { return f(x); };
int y = 123;
int& z = g(y); // reference to `y`
decltype(auto)
decltype(auto)
结合了 decltype
和 auto
的特性,允许编译器推导出一个更精确的类型
auto
会推断出返回值的类型,但它会忽略引用和常量性decltype
会根据表达式的实际类型推导,包括引用和常量性
使用场景
- 函数返回类型推导:
decltype(auto)
常用于自动推导函数返回类型,特别是当返回值可能是一个引用时。 - 函数内部变量:也可以用于局部变量的类型推导。
#include <iostream>
#include <vector>
int& getElement(std::vector<int>& vec, size_t index) {
return vec[index];
}
decltype(auto) returnElement(std::vector<int>& vec, size_t index) {
return getElement(vec, index); // 使用decltype(auto),可以确保返回引用类型
}
int main() {
std::vector<int> vec = {10, 20, 30};
decltype(auto) ref = returnElement(vec, 1); // ref 是 int& 类型
std::cout << ref << std::endl; // 输出:20
ref = 50; // 修改 vec[1] 的值
std::cout << vec[1] << std::endl; // 输出:50
}
变量模板
C++14允许变量被模板化
template <typename T>
constexpr T pi = T(3.1415926535897932385); // 一个模板变量
template <typename T>
:定义一个类型模板。constexpr T pi = T(3.1415926535897932385);
:这是模板变量的定义,pi
是常量变量,其类型依赖于模板参数T
,并且可以在不同类型下进行实例化。
示例
#include <iostream>
// 定义一个模板变量 pi
template <typename T>
constexpr T pi = T(3.1415926535897932385);
int main() {
std::cout << "pi<double>: " << pi<double> << std::endl; // 适用于 double 类型
std::cout << "pi<float>: " << pi<float> << std::endl; // 适用于 float 类型
std::cout << "pi<int>: " << pi<int> << std::endl; // 适用于 int 类型(将 3.14159 截断为 3)
}
常量模板与不同类型的类型推导:
#include <iostream>
template <typename T>
constexpr T max_value = T(100); // 默认常量值为 100
int main() {
std::cout << "max_value<int>: " << max_value<int> << std::endl; // 100
std::cout << "max_value<double>: " << max_value<double> << std::endl; // 100.0
std::cout << "max_value<char>: " << max_value<char> << std::endl; // 'd'(对应的 ASCII 值)
}
结合 auto
和模板变量:
#include <iostream>
template <typename T>
constexpr T half = T(0.5); // 定义模板变量 half
int main() {
auto x = half<int>; // 根据 int 类型推导,x 将是 0
auto y = half<double>; // 根据 double 类型推导,y 将是 0.5
std::cout << "x: " << x << std::endl; // 0
std::cout << "y: " << y << std::endl; // 0.5
}
根据类型选择不同的模板变量:
#include <iostream>
template <typename T>
constexpr T zero = T(0);
template <>
constexpr double zero<double> = 0.0; // 针对 double 类型,零值为 0.0
int main() {
std::cout << "zero<int>: " << zero<int> << std::endl; // 0
std::cout << "zero<double>: " << zero<double> << std::endl; // 0.0
}
编译时整数序列
类模板 std::integer_sequence
表示一个编译时整数序列
std::make_integer_sequence<T, N>
- 创建一个类型为T
的0, ..., N - 1
序列std::index_sequence_for<T...>
- 将模板参数包转换为整数序列
将数组转换为元组:
template<typename Array, std::size_t... I>
decltype(auto) a2t_impl(const Array& a, std::integer_sequence<std::size_t, I...>) {
return std::make_tuple(a[I]...);
}
template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
decltype(auto) a2t(const std::array<T, N>& a) {
return a2t_impl(a, Indices());
}
std::make_unique
推荐使用 std::make_unique
来创建 std::unique_ptr
实例
- 避免内存泄漏:
make_unique
自动管理内存,避免忘记删除对象导致的内存泄漏。 - 避免手动调用
new
和delete
:通过直接创建unique_ptr
,不用手动调用new
或者delete
,减少了人为错误的风险。 - 异常安全:
make_unique
在异常发生时能够自动清理已分配的内存,确保代码的异常安全性。
#include <iostream>
#include <memory> // 包含 make_unique 和 unique_ptr
class MyClass {
public:
MyClass(int val) : value(val) {
std::cout << "MyClass constructed with value: " << value << std::endl;
}
void display() const {
std::cout << "Value: " << value << std::endl;
}
private:
int value;
};
int main() {
// 使用 make_unique 创建一个 unique_ptr
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(10);
ptr->display();
// unique_ptr 在作用域结束时自动释放内存
return 0;
}