美文网首页
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++17新特性

    程序喵之前已经介绍过C++11的新特性和C++14的新特性,链接如下:xxx,今天向亲爱的读者们介绍下C++17的...

  • 记一次macOS Mojave升级GCC

    目录 前言 安装GCC 最后 前言 最近迷上了泛型编程, 看到了C++11, 14, 17的很多酷炫新特性. 之前...

  • C++11/14/17新特性

    C++11/14/17常用特性 关键字 auto 让编译器根据上下文情况,确定auto变量的真正类型,可以作为函数...

  • C++14新特性的所有知识点全在这儿啦!

    前面程序喵介绍过C++11的新特性,在这里(),这篇文章介绍下C++14的新特性。 函数返回值类型推导 C++14...

  • c++11/14/17新特性(1)

    2.1auto关键字 auto expr; 当expr包含cv描述符的时候,比如const int a = 1;a...

  • c++11/14/17新特性(2)

    constexpr 优化方式 动态规划 可以做到O(N)的算法,如果想做到O(1),那么可以把计算消耗挪到编译期间...

  • 阿里巴巴面试题基础篇 C++11

    ● 请问C++11有哪些新特性? 参考回答: C++11 最常用的新特性如下: auto关键字:编译器可以根据初始...

  • 开篇第一章--开发环境

    1. Boost简介 Boost 是一款C++准标准库,其好多特性都被C++11/14/17标准所引用。Boost...

  • C++11/14新特性

    1.nullptr nullptr 出现的目的是为了替代 NULL,传统 C++ 会把 NULL、0 视为同一种东...

  • 可怕的C++

    【C++11】新特性——引入nullprt huang_xw

网友评论

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

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