C++14常用新特性
目录
一、泛型Lambda
1.类型推导
2.通用容器打印
3.通用查找函数
4.配合完美转发forward
5.编译器实现Lambda泛型原理
二、Lambda初始化捕获
1.支持移动语义
2.支持更复杂的初始化逻辑
三、decltype(auto)
四、常量表达式constexpr增强
五、string_view
C++14主要在C++11的基础上进行了一些改进和增强,这些新特性提高了代码的简洁性、可读性和表达能力。
一、泛型Lambda
在C++11中Lambda表达式的参数必须明确类型,而C++14允许使用auto来作为参数类型,实现泛型Lambda。
1.类型推导
auto add_lambda = [](const auto& x, const auto& y) {return x + y;};cout << add_lambda(2, 3) << endl; //5cout << add_lambda(3, 3.3) << endl; //6.3
- 关于auto:auto自动推导类型时会自动剔除掉引用和const属性。
2.通用容器打印
auto print_lambda = [](const auto& container) {for (const auto& item : container) {cout << item << " ";}};list<string> coler = { "Green","Red","Blue" };print_lambda(coler); // 输出:Green Red Blue
3.通用查找函数
auto find_lambda = [](const auto& container, const auto& value) {return find(begin(container), end(container), value)!= end(container);};vector<string> fruits = { "apple","orange","banana" };cout << find_lambda(fruits, "orange") << endl; //1
4.配合完美转发forward
class MyClass
{
public:MyClass(int a, string str):_a(a),_str(str){}void print(){cout << _a << " " << _str << endl;}
private:int _a;string _str;
};int main()
{auto forward_lambda = [](auto&& ... args) {return make_unique<MyClass>(std::forward<decltype(args)>(args)...);};auto smartPtr = forward_lambda(3, "Lambda");smartPtr->print(); //3 Lambdareturn 0;
}
5.编译器实现Lambda泛型原理
//当我们写:auto lambda = [](auto x, auto y) {return x * y;};//编译器会生成类似这样的代码:class CompilerGeneratedName{template<class T1,class T2>auto operator()(T1 x, T2 y) const {return x * y;}};
- lambada表达式相较于普通函数具有储存额外捕获变量的好处,在需要对多变量操作的情况下比较方便直接捕获需要操作的变量即可,其实lambda表达式在运行时编译器会将其当作一个匿名类型的类对象,内部的成员变量就是其捕获的变量,类内部有一个operator()运算符重载函数,我们调用Lambda对象时编译器其实就会调用operator()运算符重载函数。
二、Lambda初始化捕获
1.支持移动语义
- 解决只移动类型的捕获问题,例如智能指针unique_ptr类型的对象不能进行拷贝构造,只能进行移动语义,此时用C++11中的值或引用捕获则无法正确的捕获。除此之外还可以避免不必要的拷贝。
unique_ptr<int> smart_ptr = make_unique<int>(3);//error:unique_ptr不可拷贝auto lambda = [ptr]() {/* ... */};//必须使用std::move,但这样会使外部的smart_ptr无效但可使用auto lambda1 = [ptr1 = std::move(smart_ptr)](){/* ... */ };
2.支持更复杂的初始化逻辑
auto getValue = []() { return 100; };auto factory = [num = getValue()](const auto& x){return[calculated = num * x, squared = num * num](){return calculated + squared;};};auto lambda = factory(1);
三、decltype(auto)
decltype(auto)既包含了auto的简洁性,同时也保留了decltype的精确类型推导(包含引用和const属性)。
int x = 1;auto lambda = [&x]()->const int& {return x;};decltype(auto) ret = lambda();++ret; //error 因为ret的类型被精确推到为const int&
四、常量表达式constexpr增强
C++放宽了对constexpr函数的限制:允许局部变量、允许循环(while、for)、允许简单的if-else。
可以在编译器执行更复杂的运算,提升运行期性能。
constexpr int factorial(int n)
{int result = 1;for (int i = 1;i <= n;++i) {result *= i;}return result;
}int main()
{//编译时断言static_assert(factorial(3) == 6, "Factorial Error");return 0;
}
- static_assert(常量表达式,错误信息),编译时检查零运行时开销,用于模板约束、类型检查、常量验证。
五、string_view
string_view是非拥有式字符串视图,提供对字符串数据的只读访问。
关键点:
- 非拥有式:string_view对象部管理内存,只保存指向字符串的指针和字符串的大小。
- 性能优异:避免了不必要的字符串拷贝和内存分配(底层只是复制指针和大小)。
- 只读属性:不能通过string_view对象修改底层数据。
- 生命周期:必须确保底层数据的生命周期长于string_view对象,防止悬空引用。
string_view几个常见的陷阱:
string_view create_dangerous_view()
{string str("temporary str");string_view dangerous_view = str;return dangerous_view;//Error! str底层管理的数据空间已销毁//dangerous_view仍然指向被销毁的无效空间
}
void dangerous_lifetime()
{string_view dangerous_view;{string str = "temporary str";dangerous_view = str;cout << "在作用域内:" << dangerous_view << endl;}//Error 未定义行为!cout << "在作用域外:" << dangerous_view << endl;return;
}