c++高级用法

lambda函数的两种用法

  • lambda标准语法

  • auto

auto factorial = [](auto self, int n) -> int {
        return n < 2 ? 1 : n * self(self, n - 1);
    };
  • function
std::function<void(int, int)> dfs = [&](int i, int j) {
	if (mask_.at<uchar>(i, j) == 255) return;
	mask_.at<uchar>(i, j) = 255;
      for (int k = 0; k < 4; ++k)
      {
      int ii = i + ff[k][0], jj = j + ff[k][1];
      if (ii < m.rows && jj < m.cols)
	dfs(ii, jj);
      }
};
  • 如果文件存在,删除文件
#ifdef _WIN32
#include  <io.h>
#include <cstdio>
#endif

#ifdef linux
#include <unistd.h>
#include <fcntl.h>
#endif

void delete_file(std::string strFileName){
#ifdef linux
	if (access(strFileName.c_str(), F_OK) == 0)
		remove(strFileName.c_str());
#endif

#ifdef _WIN32
	if (_access(strFileName.c_str(), 0) == 0)
		remove(strFileName.c_str());
#endif

}

goto

  • a的值等于15时,程序会跳过迭代并继续执行下一次循环
 LOOP:do {
      if( a == 15) {
         // 跳过迭代
         a = a + 1;
         goto LOOP;
      }

其他编译单元就可以直接调用

__attribute__((visibility("default")))

测试

boost.cpp


#include <boost/test/included/unit_test.hpp>  
  
#include "need2test.h"
#include "need2test2.h"

need2test.h

#define BOOST_TEST_MODULE MyTestModule  
BOOST_AUTO_TEST_SUITE(MyTestSuite)  
  
BOOST_AUTO_TEST_CASE(MyTestCase1)  
{  
    BOOST_CHECK(1 + 1 == 2);  
}  
  
BOOST_AUTO_TEST_CASE(MyTestCase2)  
{  
    BOOST_CHECK(2 * 2 == 4);  
}  
  
BOOST_AUTO_TEST_SUITE_END()

-std=c++11

禁止对象的拷贝与赋值delete

struct A {
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    int a;
    A(int i) { a = i; }
};

int main() {
    A a1;
    A a2 = a1;  // 错误,拷贝构造函数被禁用
    A a3;
    a3 = a1;  // 错误,拷贝赋值操作符被禁用
}

-std=c++14

C++14引入了二进制字面量,也引入了分隔符

int a = 0b0001'0011'1010;
double b = 3.14'1234'1234'1234;

std::make_unique

struct A {};
std::unique_ptr<A> ptr = std::make_unique<A>();

多读、单写锁

struct ThreadSafe {
    mutable std::shared_timed_mutex mutex_;
    int value_;

    ThreadSafe() {
        value_ = 0;
    }

    int get() const {
        std::shared_lock<std::shared_timed_mutex> loc(mutex_);
        return value_;
    }

    void increase() {
        std::unique_lock<std::shared_timed_mutex> lock(mutex_);
        value_ += 1;
    }
};

std::exchange比swap更高效

    std::vector<int> v;
    std::exchange(v, {1,2,3,4});

std::quoted 给字符串添加双引号

cout << std::quoted(str) << endl;

"hello world"

inline
允许同一个函数或变量的定义出现在多个编译单元中

//a.h
inline void func();

//b.h
#include "a.h"
inline void func();

-std=c++17

构造函数模板推导

pair<int, double> p(1, 2.2); // before c++17
pair p(1, 2.2); // c++17 自动推导
vector v = {1, 2, 3}; // c++17

结构化绑定

std::tuple<int, double> func() {
    return std::tuple(1, 2.2);
}

int main() {
    auto[i, d] = func(); //是C++11的tie吗?更高级
    cout << i << endl;
    cout << d << endl;
}

折叠表达式

template <typename ... Ts>
auto sum(Ts ... ts) {
    return (ts + ...);
}
int a {sum(1, 2, 3, 4, 5)}; // 15
std::string a{"hello "};
std::string b{"world"};
cout << sum(a, b) << endl; // hello world

C++17引入了constexpr lambda表达式,可以用于在编译期进行计算。
有以下限制
函数体不能包含汇编语句goto语句、label、try块、静态变量、线程局部存储、
没有初始化的普通变量,不能动态分配内存,不能有new delete等,
不能虚函数

int main() { // c++17可编译
    constexpr auto lamb = [] (int n) { return n * n; };
    static_assert(lamb(3) == 9, "a");
}

namespace嵌套

namespace A {
    namespace B {
        namespace C {
            void func();
        }
    }
}

// c++17,更方便更舒适
namespace A::B::C {
    void func();)
}

__has_include预处理表达式

#if defined __has_include
#if __has_include(<charconv>)
#define has_charconv 1
#include <charconv>
#endif
#endif

std::optional<int> ConvertToInt(const std::string& str) {
    int value{};
#ifdef has_charconv
    const auto last = str.data() + str.size();
    const auto res = std::from_chars(str.data(), last, value);
    if (res.ec == std::errc{} && res.ptr == last) return value;
#else
    // alternative implementation...
    其它方式实现
#endif
    return std::nullopt;
}

std::variant
类似union的功能,但比union更高级

int main() { // c++17可编译
    std::variant<int, std::string> var("hello");
    cout << var.index() << endl;
    var = 123;
    cout << var.index() << endl;

    try {
        var = "world";
        std::string str = std::get<std::string>(var); // 通过类型获取值
        var = 3;
        int i = std::get<0>(var); // 通过index获取对应值
        cout << str << endl;
        cout << i << endl;
    } catch(...) {
        // xxx;
    }
    return 0;
}

std::optional

  • 让函数返回对象指针,异常情况下返回nullptr
std::optional<int> StoI(const std::string &s) {
    try {
        return std::stoi(s);
    } catch(...) {
        return std::nullopt;
    }
}

void func() {
    std::string s{"123"};
    std::optional<int> o = StoI(s);
    if (o) {
        cout << *o << endl;
    } else {
        cout << "error" << endl;
    }
}

std::any
C++17引入了any可以存储任何类型的单个值

int main() { // c++17可编译
    std::any a = 1;
    cout << a.type().name() << " " << std::any_cast<int>(a) << endl;
    a = 2.2f;
    cout << a.type().name() << " " << std::any_cast<float>(a) << endl;
    if (a.has_value()) {
        cout << a.type().name();
    }
    a.reset();
    if (a.has_value()) {
        cout << a.type().name();
    }
    a = std::string("a");
    cout << a.type().name() << " " << std::any_cast<std::string>(a) << endl;
    return 0;
}

std::string_view

if-switch语句初始化

// if (init; condition)

if (int a = GetValue()); a < 101) {
    cout << a;
}

string str = "Hi World";
if (auto [pos, size] = pair(str.find("Hi"), str.size()); pos != string::npos) {
    std::cout << pos << " Hello, size is " << size;
}

折叠表达式

template <typename ... Ts>
auto sum(Ts ... ts) {
    return (ts + ...);
}
int a {sum(1, 2, 3, 4, 5)}; // 15
std::string a{"hello "};
std::string b{"world"};
cout << sum(a, b) << endl; // hello world

新增Attribute

  • [[fallthrough]],用在switch中提示可以直接落下去,不需要break,让编译期忽略警告
  • [[nodiscard]] :表示修饰的内容不能被忽略,可用于修饰函数,标明返回值一定要被处理
  • [[maybe_unused]] :提示编译器修饰的内容可能暂时没有使用,避免产生警告

C++17使用as_const可以将左值转成const类型

std::string str = "str";
const std::string& constStr = std::as_const(str);

-std=c++20

默认生成一系列的比较运算符
即:==,!=,<,>,<=,>=
自定义时有三种可用的返回类型:

  • std::strong_ordering:强比较,严格按照比较的顺序、方式来进行,不能从下面两个转回,特别注意的是它不区分等价值。
  • std::weak_ordering:弱比较,对比较的大小写,可以对等价的字符串用某种方式区别
  • std::partial_ordering:偏序比较,其实就是自定义,把直观上不可能比较的对象通过某种方式来进行比较
auto operator<=>(const Point&) const = default;

class TotallyOrdered : Base {
    std::string tax_id;
    std::string first_name;
    std::string last_name;
public:
    TotallyOrdered(const std::string& id, const std::string& first, const std::string& last)
        :tax_id(id), first_name(first), last_name(last) {}
    // 定制 operator<=>,因为我们想先比较姓
    std::strong_ordering operator<=>(const TotallyOrdered& that) const {
        if (auto cmp = (Base&)(*this) <=> (Base&)that; cmp != 0) return cmp;
        if (auto cmp = last_name <=> that.last_name; cmp != 0) return cmp;
        if (auto cmp = first_name <=> that.first_name; cmp != 0) return cmp;
        return tax_id <=> that.tax_id;
    }
    // ……非比较函数……
};

constexpr std::weak_ordering operator<=>(Rational_2 lhs, Rational_2 rhs)
{
    return lhs.num * rhs.den <=> rhs.num * lhs.den;
}

模板

  • 可以使用省略号运算符 (...) 定义采用任意数量的零个或多个类型参数的模板:
template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
  • C++ 模板支持非类型参数,也称为值参数
    • size_t 值在编译时作为模板参数传入,必须是 const 或 constexpr 表达式。
template<typename T, size_t L>
class MyArray
{
    T arr[L];
public:
    MyArray() { ... }
};


MyArray<MyClass*, 10> arr;
  • 模板作为模板参数
template<typename T, template<typename, int> class Arr>
class MyClass2
{
    T t; //OK
    Arr<T, 10> a;
};
  • 默认模板自变量
template<typename A = int, typename B = double>
class Bar
{
    //...
};
...
int main()
{
    Bar<> bar; // use all default type arguments
}
  • 例如,std::vector 模板有一个用于分配器的默认自变量:
template <class T, class Allocator = allocator<T>> class vector;
posted @ 2023-04-07 10:34  InsiApple  阅读(100)  评论(0编辑  收藏  举报