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]:	通过复制方式捕获当前对象;
posted @   DL1024  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
点击右上角即可分享
微信分享提示