摘要:本文将详细阐述C++中的yield关键字,探讨其如何在代码中实现协程和生成器等功能。首先,我们将介绍yield的基本概念,然后讨论其与协程的关系,接着将深入探讨如何使用yield实现生成器和状态机,最后对全文进行总结归纳。
1、yield基本概念
yield关键字是C++11中新增的一个关键字,其作用是将当前函数的执行权返回给调用者,同时保存当前函数的所有状态。当然,调用者必须也是一个可以暂停执行的函数,否则就没有继续执行的机会了。
yield的具体语法如下:
T yield<T>(Args... args);
其中T表示返回值类型,而Args表示函数参数列表,yield的返回值类型和参数类型根据具体情况而定。
2、yield与协程
协程是指一种可以在函数中暂停执行、保存当前状态,然后在需要的时候恢复执行的机制。通过协程,我们可以在一个函数中实现多个逻辑流程,提高代码的可读性和可维护性。
在C++中,yield关键字可以用来实现协程。我们可以使用yield将当前函数的执行权交给外部调用者,然后保存当前函数的所有状态,当再次需要执行时,恢复函数的状态,继续执行。
在执行流程上,协程的实现和线程非常相似,但协程是由程序自己控制的,不会像线程那样被操作系统调度。这使得协程的切换速度非常快,非常适合在实现IO密集型任务时使用。
3、yield实现生成器和状态机
在C++中,我们可以使用yield实现生成器和状态机。生成器是指一种可以按照某种规则生成一组数据的工具,比如Python中的生成器。而状态机是指一种可以按照预设的状态转移规则,自动进行状态转移的程序。
基于yield,我们可以比较方便地实现这两种工具。以生成器为例,我们可以使用yield将一组数据以迭代器的形式返回给调用者:
template <typename T>class Generator {
public:
struct Promise {
T value;
std::suspend_always yield_value(T value) {
this->value = value;
return {};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
Generator get_return_object() { return Generator{this}; }
void unhandled_exception() {}
};
Generator() = default;
Generator(const Generator &) = delete;
Generator &operator=(const Generator &) = delete;
Generator(Generator &&other) noexcept : coro{other.coro}, promise{other.promise} {
other.coro = nullptr;
}
Generator &operator=(Generator &&other) noexcept {
coro = other.coro;
promise = other.promise;
other.coro = nullptr;
return *this;
}
~Generator() {
if (coro) coro.destroy();
}
T operator()() {
coro.resume();
return promise.value;
}
private:
explicit Generator(Promise *promise) : promise{promise} {
coro = std::coroutine_handle::from_promise(*promise);
}
std::coroutine_handle coro{nullptr};
Promise *promise;
};
在这里,Generator是生成器类,其返回值为迭代器T。在Generator中,我们定义了Promise结构体,通过这个结构体,我们可以保存yield的返回值,以及实现initial_suspend和final_suspend等函数。在initial_suspend和final_suspend中,我们分别使用std::suspend_never返回,因为生成器不需要在协程挂起时进行任何操作。在yield_value中,我们将yield的返回值保存在value变量中,然后使用std::suspend_always返回一个协程挂起,以便调用者能够获取到yield的返回值。最后,在get_return_object中,我们返回一个Generator对象,以便调用者可以通过这个对象来迭代生成器。
类似地,我们也可以使用yield来实现状态机。例如,下面的代码中,我们定义了一个状态机类,该状态机可以按照预设的状态转移规则(使用yield定义)自动进行状态转移:
class StateMachine {public:
void run() {
for (;;) {
switch (state) {
case 0: {
std::cout << "State 0\n";
state = co_yield '0';
break;
}
case 1: {
std::cout << "State 1\n";
state = co_yield '1';
break;
}
case 2: {
std::cout << "State 2\n";
state = co_yield '2';
break;
}
default: {
std::cout << "Unknown state\n";
return;
}
}
}
}
private:
int state{0};
};
在这里,我们定义了一个StateMachine类,该类定义了三个状态,每个状态可以通过yield返回对应的状态值,并将当前状态保存下来。当下一次调用时,根据当前状态,继续执行相应的代码。
4、总结归纳
通过本文的阐述,我们了解了在C++中,yield关键字可以用来实现协程和生成器等功能。与其他语言相比,C++中的yield的实现方式较为灵活,既可以使用预定义的yield语法实现协程,也可以通过自定义Promise结构体等手段来实现各种特定的需求。
在使用yield时需要注意的是,yield关键字只能在协程中使用,同时yield是一种单向的暂停机制,每个yield只会暂停一次,如果需要多次暂停,需要写多个yield。在使用生成器和状态机时,也需要对yield的返回值有所了解,以确保代码的正确性。
本文由捡漏网https://www.jianlow.com整理,帮助您快速了解相关知识,获取最新最全的资讯。