美文网首页
C++11/14/17新特性

C++11/14/17新特性

作者: 奥利奥蘸墨水 | 来源:发表于2022-01-19 17:30 被阅读0次

    C++11/14/17常用特性

    关键字

    auto

    让编译器根据上下文情况,确定auto变量的真正类型,可以作为函数的返回值。

    std::map<uint64_t, std::vector<int>> mp;
    
    // old
    std::map<uint64_t, std::vector<int>>::iterator iter = mp.begin();
    // new
    auto iter = mp.begin();
    
    // 修饰引用
    int a = 3;
    auto& b = a;
    const auto& c = a;
    
    // 用于需要迭代的场景
    for (auto& iter : mp) {}
    
    std::vector<int> vec;
    std::sort(vec.begin(), vec.end(), [](const auto& x, const auto& y) {
        return x < y;
    });
    
    // 用于函数返回值
    auto addOne(int x)  {
        return x + 1;
    }
    
    auto addOne(int x) -> int  {
        return x + 1;
    }
    

    final

    C++11中允许将类标记为final,直接在写方法的类名之后使用关键字final,表示此类不能被继承,如果误继承此类,编译器会报错。也可以用来修饰虚函数,表示此虚函数不能被重写。

    // 修饰类
    class A final {};
    
    class B : public A {}; // compile error
    
    // 修饰虚函数,不能修饰一般函数
    class A {
    public:
        virtual void func() final {} 
    };
    
    class B : public A {
    public:
        void func() override {} // compile error
    };
    

    override

    如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法编译通过。

    class A {
    public:
        virtual void funcA() {}
        virtual void funcB() const {}
        void funcC() {}
    };
    
    class B : public A {
    public:
        void funcA() override {}
        void funcB() override {} // error, void funcB() const override {}
        void funcC() override {} // error, funcC is not virtual function
    };
    

    default / delete

    ● 将函数声明为=default会显示地告诉编译器要为该类生成默认的函数
    ● 将函数声明为=delete将告诉编译器禁用该函数

    class A {
    public:
        explicit A() = default;
        explicit A(int i) : i(i) {}
    
        A(const A& other) = delete;
        void* operator new(size_t) = delete;
    
    private:
        int i;
    };
    
    int main() {
        A a1;
        A a2(2);
        A a3(a2); // compile error
        A* a4 = new A(); // compile error
    
        return 0;
    }
    

    explicit

    禁止隐式类型转换

    class A {
    public:
        A(int i) : i(i) {}
    private:
        int i;
    };
    
    void func(const A& a) {
        // ...
    }
    
    int main() {
        func(1); // 发生隐式转换
        return 0;
    }
    
    class A {
    public:
        explicit A(int i) : i(i) {}
    private:
        int i;
    };
    
    void func(const A& a) {
        // ...
    }
    
    int main() {
        func(1); // compile error
        return 0;
    }
    

    using

    C++11新增类似于typedef的功能,用于给类型命名。比typedef多的功能是可以定义带有模板的别名。

    using Score = size_t;
    
    template <typename T1, typename T2>
    class B{};
    
    template <typename T>
    using FloatB = B<T, float>;
    
    template <typename T>
    FloatB<T> func(const Score& score) {
        // ...
    }
    
    template <typename T>
    typedef B<T, float> FloatB2; // compile error, typedef 不能定义带有模板的别名
    

    decltype

    类型推导

    struct T {
        int a;
    } ;
    
    int main() {
        decltype(3) a;
        decltype(a) b;
        
        T t;
        decltype(t.a) c;
    
        return 0;
    }
    

    nullptr / nullptr_t

    nullptr是专门一个表示空的值, 而nullptr_t是nullptr的类型

    class A {};
    
    void func(A* a) {
        std::cout << "1";
    }
    
    void func(long long i) {
        std::cout << "2";
    }
    
    int main() {
        func(NULL); // 2
        func(nullptr); // 1
    
        decltype(NULL) a; // long long
        decltype(nullptr) d; // nullptr_t 
    
        return 0;
    }
    

    constexpr

    编译器常量表达式,可作用于函数返回值,函数参数,数据申明以及类的构造函数,条件表达式。

    constexpr int a = 10;
    constexpr int b = 20;
    // 编译期的斐波那契数列
    constexpr int func(int i) {
        if (i <= 1) {
            return i;
        } else if (i == 2) {
            return 1;
        } else {
            return func(i - 1) + func(i - 2);
        }
    }
    
    int main() {
        auto t1 = func(a);
        auto t2 = func(b);
        cout << t1 << endl;
        cout << t2 << endl;
        return 0;
    }
    
    // 用于条件表达式 if constexpr() {}
    template <typename T>
    std::enable_if_t<std::is_integral_v<T>, void> func(T a) {
        if (a == 0) {
            // ...
        } else if (a <= std::numeric_limits<int8_t>::max() && a >= std::numeric_limits<int8_t>::min()) {
            // ...
        } else if (a <= std::numeric_limits<int16_t>::max() && a >= std::numeric_limits<int16_t>::min()) {
            // ...
        } else if constexpr(std::is_same_v<T, int32_t>) {
            // ...
        } else {
            // ...
        }
    }
    

    mutable

    让变量在一个const函数中也可以被修改。

    class A {
    public:
        [[nodiscard]] int get() const {
            times++; // error
            return i;
        }
    
    private:
        int i {0};
        int times {0};
    };
    
    // 正确做法
    class A {
    public:
        [[nodiscard]] int get() const {
            times++;
            return i;
        }
    
    private:
        int i {0};
        mutable int times {0};
    };
    

    模板

    通用

    template <typename T1, typename T2>
    void add(T1 t1, T2 t2) {
        cout << "result: " << t1 + t2 << endl;
    }
    
    template <typename T, int size, auto cmpFunc>
    class A {
    public:
        void sort() {
            std::sort(vec.begin(), vec.end(), cmpFunc);
        }
    private:
        std::vector<T> vec;
        std::array<T, size> arr{};
    };
    
    bool cmpFunc(const int& a, const int& b) {
        return a < b;
    }
    
    int main() {
        // 调用模板函数
        add(1, 2); // 3
        add(std::string("123"), std::string("456")); // "123456"
    
        // 调用模板类
        A<int, 10, cmpFunc> a;
    
        return 0;
    }
    

    可变长模板

    模板数量可变的模板

    template <typename T>
    void print(T t) {
        cout << "value: " << t << endl;
    }
    
    template <typename T, typename ...Types>
    void print(T head, Types ...tail) {
        cout << "value: " << head << endl;
        print(tail...);
    }
    
    int main() {
        print("1", 2, "abc", 1234, 3.01);
        return 0;
    }
    
    // 输出
    value: 1
    value: 2
    value: abc
    value: 1234
    value: 3.01
    

    sizeof...

    sizeof...可以求出可变长模板参数的个数。

    template <typename T>
    void print(T t) {
        cout << "value: " << t << endl;
    }
    
    template <typename T, typename ...Types>
    void print(T head, Types ...tail) {
        cout << "tail size: " << sizeof...(tail);
        cout << "  value: " << head << endl;
        print(tail...);
    }
    
    int main() {
        print("1", 2, "abc", 1234, 3.01);
        return 0;
    }
    
    // 输出
    size: 5  value: 1
    size: 4  value: 2
    size: 3  value: abc
    size: 2  value: 1234
    value: 3.01
    

    折叠表达式

    // 二元
    template <typename... T>
    int add(T... value) {
        return (value + ... + 3);
    }
    
    int main() {
        auto res = add(1, 2, 3, 4, 5);
        cout << res << endl; // 18
        return 0;
    }
    
    // 一元
    template <typename T>
    void do_print(T value) {
        cout << value << endl;
    }
    
    template <typename... T>
    void print(T... value) {
        (do_print(value), ...);
        (..., do_print(value));
    }
    
    int main() {
        print(1, 2, "3", "abc");
        return 0;
    }
    
    // 输出
    1
    2
    3
    abc
    1
    2
    3
    abc
    

    模板的模板参数

    template <typename T>
    using TransFunc = std::function<T(const std::string&)>;
    
    template <typename T, template<typename> typename Algorithm>
    std::enable_if_t<std::is_arithmetic_v<T>, TransFunc<T>> calculate(T a, T b) {
        auto func = Algorithm<T>();
        return [a, b, func](const std::string& str) {
            T x = std::stoul(str);
            return func(b, func(x, a));
        };
    }
    
    template <typename T>
    struct MyMinus {
        T operator()(const T& a, const T& b) const {
            return a + 3 - b;
        }
    };
    
    template<>
    struct MyMinus<double> {
        double operator()(const double& a, const double& b) const {
            return a * 2 - b;
        }
    };
    
    int main() {
        auto func1 = calculate<int, std::minus>(3, 4);
        auto res1 = func1("3");
        cout << "res: " << res1 << endl;
    
        auto func2 = calculate<double, MyMinus>(3.0, 4.0);
        auto res2 = func2("4");
        cout << "res: " << res2 << endl;
    }
    

    type_tratis

    类型萃取

    template <typename T, T v>
    struct integral_constant {
        static constexpr T value = v;
    
        using value_type = T;
        using type = integral_constant<T, v>;
    
        constexpr operator value_type() const noexcept {
            return value;
        }
    
        constexpr value_type operator()() const noexcept {
            return value;
        }
    };
    
    template <bool B>
    using bool_constant = integral_constant<bool, B>;
    
    using true_type = bool_constant<true>;
    using false_type = bool_constant<false>;
    
    template <typename T>
    struct is_void : false_type {};
    
    template <>
    struct is_void<void> : true_type {};
    
    template <>
    struct is_void<void const> : true_type {};
    
    template <>
    struct is_void<void volatile> : true_type {};
    
    template <>
    struct is_void<void const volatile> : true_type {};
    
    template <typename T>
    inline constexpr bool is_void_v = is_void<T>::value;
    

    函数式编程

    让函数成为第一类型,函数像其他对象一样可以进行传递。

    lambda表达式

    利用lambda表达式可以方便的定义和创建匿名函数。

    格式
    [捕获列表](参数列表) -> 返回类型(可省略) {
        函数体
    }
    
    捕获

    ● 按值捕获:将原值进行了拷贝保存到lambda,在函数体内不可以被改变。如果想要改变这个值,可以加上mutable关键字,但是只会改变这份拷贝,不影响被捕获的那个原始的值。
    ● 按引用捕获:捕获值的引用,对该值修改会同时修改被捕获的原始的值。坑:不要将捕获局部变量的lambda传递到其他函数中使用,要考虑局部变量的生命周期。

    int main() {
        int a = 3;
        int b = 4;
    
        auto func = [a, &b]() -> int {
            b = 7;
            // a = 4; compile error
            return a + b;
        };
    
        std::cout << func() << std::endl; // 10
        std::cout << a << std::endl; // 3
        std::cout << b << std::endl; // 7
    
        return 0;
    }
    

    std::function

    std::function是一种通用的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、lambda表达式、函数指针、以及其他函数对象等。std::function对象是对C++中现有的可调用实体的一种类型安全的包裹。

    int add(int a) {
        return a + 1;
    }
    
    typedef int (*AddFunc)(int);
    AddFunc addFunc = add;
    
    struct AddClass {
        int operator()(int a) {
            return a + 1;
        }
    };
    
    int main() {
        std::function func1 = add;
        std::function func2 = addFunc;
        std::function func3 = AddClass();
        std::function func4 = [](int a) {
            return a + 1;
        };
        
        std::function<int(int)> func5 = add; // 显示指定模板
        std::function<int(int)> func6 = addFunc; 
    
        std::cout << func1(3) << std::endl; // 4
        std::cout << func2(3) << std::endl; // 4
        std::cout << func3(3) << std::endl; // 4
        std::cout << func4(3) << std::endl; // 4
        std::cout << func5(3) << std::endl; // 4
        std::cout << func6(3) << std::endl; // 4
    
        return 0;
    }
    

    std::bind

    可以绑定函数和参数或部分参数生成一个函数对象。

    int add(int a, int b) {
        return a + b;
    }
    
    struct AddClass {
        int operator()(int a, int b) {
            return a + b;
        }
    };
    
    int main() {
        auto func1 = std::bind(add, std::placeholders::_1, 3);
    
        auto func2 = [](int b) {
            return add(3, b);
        };
    
        AddClass addClass;
        auto func3 = std::bind(&AddClass::operator(), &addClass, std::placeholders::_1, 3);
        
        auto func4 = [addClass](int b) mutable {
            return addClass(3, b);
        };
        
        std::cout << func1(4) << std::endl;
        std::cout << func2(4) << std::endl;
        std::cout << func3(4) << std::endl;
        std::cout << func4(4) << std::endl;
    
        return 0;
    }
    
    // 输出
    7
    7
    7
    7
    

    一些函数式的库

    std::transform
    std::vector<int> vec {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    std::vector<std::pair<int, char>> result;
    std::transform(vec.begin(), vec.end(), std::back_inserter(result), [](const auto& val) {
        return std::pair{val, static_cast<char>(val - 1 + 'a')};
    });
    
    for (auto & p : result) {
        std::cout << p.first << " " << p.second << std::endl;
    }
    
    // 输出
    1 a
    2 b
    3 c
    4 d
    5 e
    6 f
    7 g
    8 h
    9 i
    10 j
    

    std::for_each / std::for_each_n

    // std::for_each 输出同上
    std::for_each(result.begin(), result.end(), [](const auto& p) {
        std::cout << p.first << " " << p.second << std::endl;
    });
    
    // std::for_each_n
    std::for_each_n(result.begin(), 3, [](const auto& p) {
        std::cout << p.first << " " << p.second << std::endl;
    });
    // 输出
    1 a
    2 b
    3 c
    

    std::any_of / std::all_of / std::none_of

    std::vector<int> vec {1, 1, 1, 3, 1, 1, 1};
    
    auto res1 = std::any_of(vec.begin(), vec.end(), [](const auto& val) {
        return val == 3;
    }); // true
    
    auto res2 = std::all_of(vec.begin(), vec.end(), [](const auto& val) {
        return val == 1; 
    }); // false
    
    auto res3 = std::none_of(vec.begin(), vec.end(), [](const auto& val) {
        return val == 3;
    }); // false
    
    
    std::count / std::count_if
    std::vector<int> vec {1, 1, 1, 3, 1, 1, 1, 4};
    
    auto num1 = std::count(vec.begin(), vec.end(), 1);
    std::cout << num1 << std::endl; // 6
    
    auto num2 = std::count_if(vec.begin(), vec.end(), [](const auto& val){
        return val < 4;
    });
    std::cout << num2 << std::endl; // 7
    

    其他

    移动构造

    智能指针

    基于范围的for循环

    enum class

    几种强转

    自定义字面量

    随机数功能

    正则表达式

    数据结构std::tuple

    结构化绑定

    if-switch语句初始化

    namespace nested

    lambda捕获this对象

    文件系统

    并发支持

    统一的字符串视图std::string_view

    std::optional

    std::any

    std::variant

    attribute

    inline全局变量

    ...

    展望C++ 20/23/...

    包管理 modules

    协程 coroutines

    概念 concept

    范围ranges & 视图views

    原子智能指针

    三路比较运算符<=>

    executors

    networking

    编译器反射 reflection

    模式匹配 pattern matching

    ...

    相关文章

      网友评论

          本文标题:C++11/14/17新特性

          本文链接:https://www.haomeiwen.com/subject/fsnrhrtx.html