对宏的唯一可识别调用



上下文

我正在尝试在我的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;
}

最新更新