C++11新特性系列
C++11/14特性系列
1. variadic templates (可变参数模板)
// 需要处理最后一个无参的情况
void print( ){
}
template <typename... Types>
void print(const Types&... args){
print("ss", args...);
}
// 可变参数模板 用于递归 (传参类型为包,可以不同)
template <typename T, typename... Types>
void print(const T &farg, const Types&... args){
cout << farg << endl;
print(args...);
}
2. auto 自动类型推导
int main( ){
vector<int> f = {1, 2, 3, 4, 5};
vector<int>::iterator ft;
ft = f.begin( );
auto it = f.begin( );
// ft 和 it 都是迭代器,auto能够自动识别推导相应的类型,进行声明
cout << *ft << endl;
cout << *it << endl;
return 0;
}
3. initializer_list<> 初始化列表
// 传递给 initializer_list,一定是 initializer_list 或者 {...} 形式
void print(std::initializer_list<int> vals){
std::cout << "here\n";
for (auto p = vals.begin( ); p != vals.end( ); ++p){
std::cout << *p << "\n";
}
}
print({1, 2, 3, 4, 5});
// --------------------------------------------------------
class P{
public:
P(int a, int b){ std::cout << "P(int, int), a = " << a << ", b = " << b << endl; }
P(initializer_list<int> initlist){
std::cout << "P(initializer_list<int>, values = ";
for (auto i : initlist){ std::cout << i << " "; }
std::cout << std::endl;
}
};
P p(77, 5); // P(int, int), a = 77, b = 5
P q{77, 5}; // P(initializer_list<int>, values = 77 5
P r{77, 5, 42}; // P(initializer_list<int>, values = 77 5 42
P s = {77, 5}; // P(initializer_list<int>, values = 77 5
如果没有 P(initializer_list<int> initlist)
, 则 P q{77, 5}
会调用 P(int a, int b)
。
4. 基于范围的for循环
for (decl : coll){ statement; }
// 例
for (int i : {2, 3, 4, 6, 7, 8, 9}){ std::cout << i << std::endl; }
vector<int> vec;
...
for (auto elem : vec){ std::cout << elem << std::endl; }
for (auto &elem : vec){
elem *= 3; // 引用可以直接修改vec中的内容
}
5. default, delete 关键字
// 如果你自定义一个 ctor,那么编译器不会再给你 default ctor
// 如果你强制加上 =default,那么就可以获得并使用 default ctor
class A{
public:
// 构造函数
A(int i_, int j_) : i(i_), j(j_){ }
// 禁用拷贝构造
A(const A &) = delete;
// 使用默认版本的移动构造
A(A &&) = default;
// 使用默认版本的拷贝赋值运算符
A &operator=(const A &) = default;
// 禁止移动赋值运算符
A &operator=(A &&) = delete;
// 析构函数
virtual ~A( ){ }
private:
int i, j;
};
6. alias 化名模板参数,类似于 typedef
// -----------------------------------------------------------
// 1. alias template
template<typename T>
using Vec = vector<T, allocator<T>>;
template<typename T>
using Mystring = std::basic_string<T, std::char_traits<T>>;
// typedef basic_string<char> string;
// -----------------------------------------------------------
// 2. type alias
// 类似于 typedef 声明,较为清楚明了
using func = void(*)(int, int); // typedef void(*func)(int, int);
void f(int a, int b){ };
func fp = f; // 可以这样声明一个 函数指针
// -----------------------------------------------------------
template <typename T>
class Container{
using value_type = T; // typedef T value_type
};
// which can be used in generic programing
template<typename Cntr>
void f2(const Cntr &c){
typename c::value_type n;
}
7. noexcept;
void foo( ) noexcept; // void foo() noexcept(true); noexcept后的为真,才不会抛出异常
// 当 a.Swap(b)不发生异常的时候,Swap不发出异常
template<typename T>
void Swap(T &a, T &b) noexcept(noexcept(a.Swap(b))){
a.Swap(b);
}
// 使用 移动构造 和 移动赋值运算符 的时候需要使用 noexcept
class Mystring{
private:
char *_data;
size_t _len;
public:
// move constructor
Mystring(Mystring &&str) noexcept : _data(str._data), _len(str._len){ ... }
// move assignment
Mystring &operator=(Mystring &&str) noexcept{ ... return *this; }
}
8. override(函数重写)
struct Base{
virtual void vfunc(float){ }
};
struct Derived1 :Base{
// 函数重写出错,函数签名不一致 声明了一个新的虚函数
virtual void vfunc(int){ } // Error,编译器不会提示错误,但是重写虚函数失败
};
struct Derived2 :Base{
virtual void vfunc(int) override{ } // Error
// override 告知编译器这个函数是对虚函数的重写,此时函数签名不一致导致重写失败
// 编译器会提示错误
virtual void vfunc(float) override{ }
};
9. final
// final 修饰 class
struct Base final{
virtual void vfunc(float){ }
};
// Base 声明被 final 之后,无法被继承
struct Derived1 :Base{ }; // Error
struct Base2{
virtual void vfunc(float) final{ }
};
struct Derived2 :Base2{
// 父类的 vfunc 声明被 final 修饰之后,无法被重写
virtual void vfunc(float) override{ } // Error
};
10. decltype
// decltype, used to declare return types;
template<typename T1, typename T2>
auto add(T1 x, T2 y)->decltype(x + y);
// decltype(x + y) add(T1 x, T2 y); Error, 此时 x y 还未声明,无法通过编译
// 类似于 lambdas 表达式的语法
// decltype, used to pass the type of a lambda
auto cmp = [ ](const int &a, const int &b){
return a < b;
};
// 对于 lambda,我们往往只有 object,没有type,可以借助 decltype 来推导类型
std::set<int, decltype(cmp)> coll(cmp);
11. lambdas 表达式
{
[ ]( ){
std::cout << "hello lambda1\n";
};
[ ]( ){
std::cout << "hello lambda2\n";
}(); // prints "hello lambda2"
auto I = [ ]( ){
std::cout << "hello lambda3\n";
};
I( ); // prints "hello lambda3"
// 标准语法 mutable throwSpec retType 可选,三个都没有可省略参数()
// [...](...)mutable_ throwSpec_ -> retType_ { ... };
}
捕获类型如下:
[]: 默认不捕获任何变量;
[=]: 默认以复制捕获所有变量;
[&]: 默认以引用捕获所有变量;
[x]: 仅以复制捕获x,其它变量不捕获;
[x...]: 以包展开方式复制捕获参数包变量;
[&x]: 仅以引用捕获x,其它变量不捕获;
[&x...]: 以包展开方式引用捕获参数包变量;
[=, &x]: 默认以复制捕获所有变量,但是x是例外,通过引用捕获;
[&, x]: 默认以引用捕获所有变量,但是x是例外,通过复制捕获;
[this]: 通过引用捕获当前对象(其实是复制指针);
[*this]: 通过复制方式捕获当前对象;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报