其他分享
首页 > 其他分享> > Lesson4

Lesson4

作者:互联网

模板类型推导

模板函数可以根据函数参数的类型推导出模板参数的类型,原理和自动类型(auto)推导是一样的。输入是左值的情况:

template <typename T>
void func1(T x) {}

template <typename T>
void func2(T& x) {}

template <typename T>
void func3(T&& x) {}

int main() {

	int x = 1024;
	
	func1(x);	// int
	func2(x);	// int&
	func3(x);	// int&
}

输入是右值的情况:

template <typename T>
void func1(T x) {}

template <typename T>
void func2(const T& x) {}

template <typename T>
void func3(T&& x) {}

int main() {
	
	func1(1024);	// int
	func2(1024);	// const int&
	func3(1024);	// int&&
}

T&& 是万能引用,原理是引用折叠。引用折叠的规则:如果两个引用都是右值引用,那么结果是右值引用,否则是左值引用。可以通过万能引用实现 std::move():

template <typename T>
decltype(auto) move(T&& x) {
	return static_cast<std::remove_reference_t<T>&&>(x);
}

如果 x 是 int 或 int& 类型(左值),则 T 是 int&,T&& 是 int& &&,根据引用折叠,也就是 int&,move() 返回 int&&。实例化的模板函数相当于:

int&& move(int& x) {
	return static_cast<int&&>(x);
}

如果 x 是 int&& 类型(右值),则 T 是 int,T&& 是 int&& &&,根据引用折叠,也就是 int&&,move() 返回 int&&。实例化的模板函数相当于:

int&& move(int&& x) {
	return static_cast<int&&>(x);
}

还可以通过万能引用实现 std::forward():

template <typename T>
decltype(auto) forward(std::remove_reference_t<T>& x) {
	return static_cast<T&&>(x);
}

template <typename T>
void func(T&& x) {
	other_func(forward<T>(x));
}

如果 x 是 int 或 int& 类型(左值),则 T 是 int&,T&& 是 int& &&,根据引用折叠,也就是 int&,forward() 返回 int&。实例化的模板函数相当于:

int& forward(int& x) {
	return static_cast<int&>(x);
}

void func(int& x) {
	other_func(static_cast<int&>(x));
}

如果 x 是 int&& 类型(右值),则 T 是 int,T&& 是 int&& &&,根据引用折叠,也就是 int&&,forward() 返回 int&&。实例化的模板函数相当于:

int&& forward(int& x) {
	return static_cast<int&&>(x);
}

void func(int&& x) {
	other_func(static_cast<int&&>(x));
}

可变参模板

有时,函数的参数个数是不确定的,可以使用可变参模板实现:

template <typename ...Args>		// 打包
void func(Args&& ...args) {		// 打包
	other_func(std::forward<Args>(args)...);	// 解包
}

线程

标准库提供了跨平台的多线程接口。一个简单的无界队列:

template <typename T>
class Queue {
public:
	template <typename T>
	void push(T&& val) {

		std::lock_guard lk{ m_ };
		q_.push(std::forward<T>(val));
		cv_.notify_one();
	}

	T pop() {

		std::unique_lock lk{ m_ };
		cv_.wait(lk, [this] { return !q_.empty(); });
		assert(!q_.empty());
		T ret{ std::move(q_.front()) };
		q_.pop();
		return ret;
	}
	
	std::optional<T> try_pop() {
		
		std::lock_guard lk{ m_ };
		if (q_.empty()) return {};
		std::optional ret{ std::move(q_.front()) };
		q_.pop();
		return ret;
	}

private:
	std::queue<T> q_;
	std::mutex m_;
	std::condition_variable cv_;
};

一个简单的有界队列:

template <typename T>
class Queue {
public:
	Queue(int capacity) : q_{ capacity } {}

	template <typename T>
	void push(T&& val) {

		std::unique_lock lk{ m_ };
		not_full_.wait(lk, [this] { return !q_.full(); });
		q_.push_back(std::forward<T>(val));
		not_empty_.notify_one();
	}

	T pop() {

		std::unique_lock lk{ m_ };
		not_empty_.wait(lk, [this] { return !q_.empty(); });
		T ret = std::move(q_.front());
		q_.pop_front();
		not_full_.notify_one();
		return ret;
	}

	template <typename T>
	bool try_push(T&& val) {

		std::lock_guard lk{ m_ };
		if (q_.full()) return false;
		q_.push_back(std::forward<T>(val));
		not_empty_.notify_one();
		return true;
	}

	std::optional<T> try_pop() {

		std::lock_guard lk{ m_ };
		if (q_.empty()) return {};
		std::optional ret{ std::move(q_.front()) };
		q_.pop_front();
		not_full_.notify_one();
		return ret;
	}

private:
	boost::circular_buffer<T> q_;
	std::mutex m_;
	std::condition_variable not_empty_;
	std::condition_variable not_full_;
};

一个简单的计数器:

class CountDown {
public:
	CountDown(int n) : n_(n) {}

	void wait() {
		std::unique_lock lk{ m_ };
		cv_.wait(lk, [this] { return n_ == 0; });
	}

	void down() {
		std::lock_guard lk{ m_ };
		if (--n_ == 0) cv_.notify_all();
	}
	
private:
	int n_;
	std::mutex m_;
	std::condition_variable cv_;
};

一个简单的线程池:

class ThreadPool {
public:
	using task = std::function<void()>;

	ThreadPool(int n) : q_{ n }, running_{ false } {}

	~ThreadPool() {
		if (running_) stop();
	}

	void start(int n) {

		running_ = true;
		threads_.reserve(n);
		while (n--) {
			threads_.push_back(std::thread(&ThreadPool::work, this));
		}
	}

	void stop() {

		{
			std::lock_guard lk{ m_ };
			running_ = false;
			not_empty_.notify_all();
			not_full_.notify_all();
		}
		for (auto& t : threads_) {
			t.join();
		}
	}
	
	template <typename T>
	void run(T&& t) {

		std::unique_lock lk{ m_ };
		not_full_.wait(lk, [this] { return !q_.full() || !running_; });
		if (!running_) return;
		q_.push_back(std::forward<T>(t));
		not_empty_.notify_one();
	}

private:
	void work() {

		while (true) {
			task t;
			{
				std::unique_lock lk{ m_ };
				not_empty_.wait(lk, [this] { return !q_.empty() || !running_; });
				if (!running_) return;
				t = std::move(q_.front());
				q_.pop_front();
				not_full_.notify_one();
			}
			t();
		}
	}

	std::vector<std::thread> threads_;
	boost::circular_buffer<task> q_;
	bool running_;
	std::mutex m_;
	std::condition_variable not_empty_;
	std::condition_variable not_full_;
};

标签:std,return,Lesson4,int,lk,_.,&&
来源: https://blog.csdn.net/m0_37957950/article/details/122584555