上下文
我正在尝试在我的C++代码中实现一种易于使用的async/await
模式,并且我有一种方法可以做到这一点,我觉得使用起来非常简单。但是,由于我使用的是宏,因此在针对外来代码的弱点方面也付出了代价。
这是这个想法:
- 我们将执行上下文包装在一个类中,该类的成员是
async
函数使用的变量。 -
在我使用宏实现的
async
函数主体中,我用来跟踪恢复函数执行时跳转到的位置的成员entrypoint
开关:switch(this->entrypoint) { // All the async code occurs here, like: await(this->foo = bar()); std :: cout << this->foo << std :: endl; await(this->foo2 = bar2()); std :: cout << this->foo2 << std :: endl; }
-
await(assignment)
宏实际上以以下形式定义了某些内容:this->entrypoint = (some value x); return; case x:
现在,这显然不如我们在 Javascript 中可以拥有的成熟async function
那么紧凑,但它足以满足我的需求。此外,这可以防止嵌套开关(我很少使用),并且您无法在本地定义变量,除非您以某种方式将它们包装在{ /*..*/ }
中。但是我得到了一种超级紧凑的方式来执行具有同步样式的异步操作。
备注:这个策略的缺点和缺点对我来说很清楚,这不是我问题的重点,我只是添加这个来帮助了解我需要什么。
问题
上面的编译和运行良好。但是,我遇到了一个严重的问题:在await
宏中,我需要生成一些唯一值x
以在case
语句中使用。到目前为止,我正在使用__LINE__
,它工作得很好,可以防止大多数实际目的的碰撞。但是,当您在同一行上编写两个await
语句时会发生什么?
所以我想知道:有没有比使用__LINE__
唯一标识对宏的调用更好的方法,这样每当我从代码中的两个不同位置调用同一个宏时,我都会得到不同的值扩展?
模板实例化(不稳定)
类型系统提供了创建编译时变量的方法;但是,它不提供任何在调用之间维护状态的方法。
但是,使用这里描述的方法,您可以通过检查已创建哪些函数来在模板系统中创建一个constexpr
计数器,这些函数可能对您有用;但是,该系统依赖于 gcc 生成函数的方式的一些承诺,并且将来可能无法工作,它目前在 clang 上失败。
因为这里的所有内容都在编译时运行(主要是在类型系统中),所以你既可以在 switch 语句中使用值,又可以在运行时(几乎)零开销。
宏生成函数(全局范围)
这篇文章描述了一种完全由宏制作编译时计数器的方法;然而,为了使值constexpr
它会产生新的函数,并且只能从函数的外部递增。
__COUNTER__
延长
预处理器的标准没有提供请求唯一值的方法;但是,如注释中所述,GCC具有将执行所请求任务的__COUNTER__
扩展。Visual Studio和Clang也支持这一点。
不使用开关
一个简单的解决方法(尽管我对你的实现不够了解)可能是删除 switch 语句,以支持链接的 else if 集。
#define aswitch(x)
int position_counter=0;
if(this->entrypoint==position_counter++)
#define await(x)
this->entrypoint=position_counter;
}else if(this->entrypoint==position_counter++){
aswitch(this->entrypoint)
{
await(bar());
std :: cout << this->foo << std :: endl;
await(bar2());
std :: cout << this->foo2 << std :: endl;
}