乐趣区

关于c++:c11强化知识点

初始化列表(std::initializer_list)

  • c++11 提供了 std::initializer_list,将使得类对象的初始化也能够和一般数组或者 POD 数据一样应用初始化列表的形式。只有为类对象提供初始化列表构造函数即可。
  • std::initializer_list 也能够作为函数的参数应用。
  • 初始化列表 std::initializer_list 相干示例代码如下。
#include <iostream>
#include <initializer_list>
#include <vector>

using namespace std;

class InitClass {
public:
    InitClass(initializer_list<int> list) {for (int l : list)
            initializer_list_.emplace_back(l);
    }

    void PrintInit() {for (int l : initializer_list_)
            cout << l << endl;
    }

    void Print(initializer_list<int> list) {for (int l : list)
            cout << l << endl;
    }

private:
    vector<int> initializer_list_;
};

struct A {
    double a;
    int b;
};
struct B {B(int a, double b): a_(a), b_(b) {}
private:
    int a_;
    double b_;
};


int main()
{
    // 应用初始化列表初始化类对象
    InitClass i = {1, 2, 3, 4, 5};
    i.PrintInit();
    cout << endl;
    // 初始化列表做函数参数
    i.Print({1, 2, 3});
    // 应用初始化列表初始化 POD 数据
    vector<int> v = {1, 2, 3, 4};
    A a {1.1, 1};
    B b {2, 2.2};
    
    return 0;
}

变长参数模板(typename… Args)

  • c++11 提供了变长参数模板,堪比黑魔法。能够实现任意类型、任意个数的变长参数模板类和函数。
  • 能够应用经典的递归模板函数的形式去取出变长参数模板函数中的参数,示例代码如下。
#include <iostream>
template<typename T>
void printf(T value) {std::cout << value << std::endl;}
template<typename T, typename... Args>
void printf(T value, Args... args) {
    std::cout << value << std::endl;
    printf(args...);
}
int main() {printf(1, 2, "123", 1.1);
    return 0;
}
  • c++14 提供了更简便的办法,能够应用初始化列表开展变长参数,示例代码如下。
// 编译这个代码须要开启 -std=c++14
#include <iostream>
template<typename T, typename... Args>
auto print(T value, Args... args) {
    std::cout << value << std::endl;
    return std::initializer_list<T>{([&] {std::cout << args << std::endl;}(), value)...};
}
int main() {print(1, 2.1, "123");
    return 0;
}

强类型枚举(enum class)

  • c++11 提供了类型平安的枚举类 enum class。枚举类中定义的枚举值不可能被隐式转换为整数,也不能与整数间接比拟,更不能与不同的枚举类型的枚举值比拟。
  • 枚举类定义的枚举值能够定义雷同的值。
  • 枚举类中能够本人定义枚举值的类型,默认是 int。
  • 能够通过重载 << 运算符来实现间接打印枚举类的值。
  • 能够定义模板转换函数来不便将枚举类的枚举值与根本数据类型(如 int)间接进行比拟。
  • 所有示例代码如下。
#include <iostream>
enum class new_enum : unsigned int {
    value1,
    value2,
    value3 = 888,
    value4 = 888
};

template<typename T>
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) {return stream << static_cast<typename std::underlying_type<T>::type>(e);
}

template<typename T>
auto to_underlying_type(const T& e) {return static_cast<typename std::underlying_type<T>::type>(e);
}

int main() {if (new_enum::value3 == new_enum::value4 && 888 == to_underlying_type(new_enum::value3))
    {std::cout << new_enum::value3 << std::endl;}
    return 0;
}

函数对象包装器(std::function)

  • c++11 提供了能够定义任意可调用类型的函数对象包装器(std::function),这是对函数对象的一种类型平安的包装。
  • 利用 std::function 和 c ++11 提供的更弱小的 using 语法以及 Lambda 函数,咱们能够更不便的实现类对象中的简略的回调函数。示例代码如下。
#include <iostream>
#include <memory>

class A {
public:
    using CallBack = std::function<void()>;

    void SetCallBack(CallBack cb) {call_back_ = cb;}
    void CallCallBack() {if (call_back_)
        {call_back_();
        }
        
    }

private:
    CallBack call_back_ = nullptr;
};

class B {
public:
    B() {a = std::make_shared<A>();
        a->SetCallBack([](){std::cout << "call A cb in B" << std::endl;});
        a->CallCallBack();}

private:
    std::shared_ptr<A> a = nullptr;
};

int main() {B b;}
  • 如果回调函数很简单,不适宜用 Lambda 函数实现,也能够通过 std::bind 来将回调函数绑定到类的成员函数上。

智能指针初始化(make_unique)

  • 为了简化 c ++ 的指针治理,c++11 扩大了规范库,推出了智能指针——std::shared_ptr/std::unique_ptr/std::weak_ptr。智能指针应用援用计数的形式来实现主动开释资源,使得 c ++ 语言更具现代性。
  • 规范库提供了 std::make_shared 来初始化一个 std::shared_ptr,防止了咱们应用 new 来初始化 std::shared_ptr。然而因为“被规范委员会遗记了”,规范库却没有提供 make_unique 的办法来给咱们初始化一个 std::unique_ptr(好在 c ++14 提供了)。为此咱们能够本人实现一个 make_unique,代码如下。
#include <memory>

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args) {return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

int main() {std::unique_ptr<int> p = make_unique<int>(1);
    return 0;
}
退出移动版