Modern C++学习笔记(一)

一些用法

语言可用性的强化

变量及其初始化

初始化列表

MagicFoo(std::initializer_list<int> list) {
        for (std::initializer_list<int>::iterator it = list.begin(); it != list.end(); ++it)
            vec.push_back(*it);
}
MagicFoo magicFoo = {1, 2, 3, 4, 5};
public:
    void foo(std::initializer_list<int> list) {
        for (std::initializer_list<int>::iterator it = list.begin();
            it != list.end(); ++it) vec.push_back(*it);
    }

magicFoo.foo({6,7,8,9});

结构化绑定

#include <iostream>
#include <tuple>
std::tuple<int, double, std::string> f() {
    return std::make_tuple(1, 2.3, "456");
}
int main() {
    auto [x, y, z] = f();
    std::cout << x << ", " << y << ", " << z << std::endl;
    return 0;
}

类型推导

auto x = 1;
auto y = 2;
decltype(x+y) z;//计算某个表达式的类型
或者  
std::is_same<decltype(x), decltype(z)>::value //用于判断 T 和 U 这两个类型是否相等
//C++11
template<typename T, typename U>
auto add2(T x, U y) -> decltype(x+y){
    return x + y;
}
//C++14
template<typename T, typename U>
auto add3(T x, U y){
    return x + y;
}
//在 C++11 中,封装实现是如下形式:

std::string look_up_a_string_1() {
    return lookup1();
}
std::string& look_up_a_string_2() {
    return lookup2();
}

//而有了 decltype(auto),我们可以让编译器完成这一件烦人的参数转发:

decltype(auto) look_up_a_string_1() {
    return lookup1();
}
decltype(auto) look_up_a_string_2() {
    return lookup2();
}
if constexpr (std::is_integral<T>::value) {
        return t + 1;
}
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4};
    if (auto itr = std::find(vec.begin(), vec.end(), 3); itr != vec.end()) *itr = 4;
    for (auto element : vec)
        std::cout << element << std::endl; // read only
    for (auto &element : vec) {
        element += 1;                      // writeable
    }
    for (auto element : vec)
        std::cout << element << std::endl; // read only
}

模板

template class std::vector<bool>;          // 强行实例化
extern template class std::vector<double>; // 不在该当前编译文件中实例化模板
template<typename T>
using TrueDarkMagic = MagicType<std::vector<T>, std::string>;

int main() {
    TrueDarkMagic<bool> you;  // 使用模板别名,生成一个类型为 MagicType<std::vector<bool>, std::string> 的变量
}
template<typename... Ts> class Magic;

如果不希望产生的模板参数个数为 0,可以手动的定义至少一个模板参数。
除了在模板参数中能使用 … 表示不定长模板参数外, 函数参数也使用同样的表示法代表不定长参数, 这也就为我们简单编写变长参数函数提供了便捷的手段。

template<typename... Args> void printf(const std::string &str, Args... args);

对参数进行解包,到目前为止还没有一种简单的方法能够处理参数包,但有两种经典的处理手法:
1)递归模板函数
2)变参模板展开

template<typename T0, typename... T>
void printf2(T0 t0, T... t) {
    std::cout << t0 << std::endl;
    if constexpr (sizeof...(t) > 0) printf2(t...);
}

事实上,有时候我们虽然使用了变参模板,却不一定需要对参数做逐个遍历,我们可以利用 std::bind 及完美转发等特性实现对函数和参数的绑定,从而达到成功调用的目的。

// 使用 std::bind 将函数和参数绑定在一起
    auto bound_print = std::bind(print, 1, 2.5, "hello");
#include <iostream>
template<typename ... T>
auto sum(T ... t) {
    return (t + ...);
}
int main() {
    std::cout << sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
}

面向对象

#include <iostream>
class Base {
public:
    int value1;
    int value2;
    Base() {
        value1 = 1;
    }
    Base(int value) : Base() { // 委托 Base() 构造函数
        value2 = value;
    }
};
class Subclass : public Base {
public:
    using Base::Base; // 继承构造
};
int main() {
    Subclass s(3);
    std::cout << s.value1 << std::endl;
    std::cout << s.value2 << std::endl;
}
struct Base {
    virtual void foo(int);
};
struct SubClass: Base {
    virtual void foo(int) override; // 合法
    virtual void foo(float) override; // 非法, 父类没有此虚函数
};

struct Base {
    virtual void foo() final;
};
struct SubClass1 final: Base {
}; // 合法

struct SubClass2 : SubClass1 {
}; // 非法, SubClass1 已 final

struct SubClass3: Base {
    void foo(); // 非法, foo 已 final
};
class Magic {
    public:
    Magic() = default; // 显式声明使用编译器生成的构造
    Magic& operator=(const Magic&) = delete; // 显式声明拒绝编译器生成构造
    Magic(int magic_number);
}
enum class new_enum : unsigned int {
    value1,
    value2,
    value3 = 100,
    value4 = 100
};

而我们希望获得枚举值的值时,将必须显式的进行类型转换,不过我们可以通过重载 « 这个算符来进行输出

//可以收藏下面这个代码段!!!!!!
#include <iostream>
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);
}
这时,下面的代码将能够被编译:

std::cout << new_enum::value3 << std::endl