如何设计一个;“等待”;基类? < C++ >标准库在很多地方提供了一种“可等待”的API:例如:代码> STD::“未来和 STD::条件Buffic变量可以立即“尝试”以获得它们的值,“等待”它们的值不明确,“Waigi”为某个代码> STD:::Simul::持续时间< /> >,或“WaITI~”。达到某个std::chrono::time\u点。我正在努力创建一个抽象基类来捕获这些相同的操作 template <typename T> class awaitable { public: virtual std::optional<T> try() = 0; virtual std::optional<T> wait() = 0; template <typename Rep, typename Period> virtual std::optional<T> wait_for(const std::chrono::duration<Rep, Period>&) = 0; template <typename Clock, typename Duration> virtual std::optional<T> wait_until(const std::chrono::time_point<Clock, Duration>&) = 0; }; 模板 等待上课{ 公众: 虚拟std::可选try()=0; 虚拟std::可选等待()=0; 模板 虚拟std::可选等待时间(const std::chrono::duration&)=0; 模板 虚拟标准::可选等待时间(常数标准::计时::时间点&)=0; };

如何设计一个;“等待”;基类? < C++ >标准库在很多地方提供了一种“可等待”的API:例如:代码> STD::“未来和 STD::条件Buffic变量可以立即“尝试”以获得它们的值,“等待”它们的值不明确,“Waigi”为某个代码> STD:::Simul::持续时间< /> >,或“WaITI~”。达到某个std::chrono::time\u点。我正在努力创建一个抽象基类来捕获这些相同的操作 template <typename T> class awaitable { public: virtual std::optional<T> try() = 0; virtual std::optional<T> wait() = 0; template <typename Rep, typename Period> virtual std::optional<T> wait_for(const std::chrono::duration<Rep, Period>&) = 0; template <typename Clock, typename Duration> virtual std::optional<T> wait_until(const std::chrono::time_point<Clock, Duration>&) = 0; }; 模板 等待上课{ 公众: 虚拟std::可选try()=0; 虚拟std::可选等待()=0; 模板 虚拟std::可选等待时间(const std::chrono::duration&)=0; 模板 虚拟标准::可选等待时间(常数标准::计时::时间点&)=0; };,c++,templates,c++17,virtual-functions,multidispatch,C++,Templates,C++17,Virtual Functions,Multidispatch,try和wait没有问题等待和等待需要模板参数,因此不能是虚拟的 有没有一种“干净”的方法来定义这样的接口` 我考虑过的一些选项(除非我遗漏了什么)似乎不可行: 使用std::any或其他类型的擦除。在内部将duration对象传递给另一个函数时,我仍然需要知道正确转换它的确切类型 使用访问者模式。这需要我指定一个硬编码列表,其中包含从一个中心位置的“waitiable”派生的所有类型,引入循环依赖项并限制可扩展性 使用std::duration\u cast和std::time\u poin

try
wait
没有问题<代码>等待和
等待
需要模板参数,因此不能是虚拟的

有没有一种“干净”的方法来定义这样的接口`

我考虑过的一些选项(除非我遗漏了什么)似乎不可行:

  • 使用
    std::any
    或其他类型的擦除。在内部将
    duration
    对象传递给另一个函数时,我仍然需要知道正确转换它的确切类型
  • 使用访问者模式。这需要我指定一个硬编码列表,其中包含从一个中心位置的“waitiable”派生的所有类型,引入循环依赖项并限制可扩展性
  • 使用
    std::duration\u cast
    std::time\u point\u cast
    将任何传入类型强制转换为
    std::chrono::nanoseconds
    std::chrono::time\u point
    ,因此将有一个非虚拟模板化方法和一个虚拟非模板化方法。这似乎会引入不必要的开销和潜在的错误行为,因为我不确定是否每个可能的传入类型都能保证对这些常见类型进行强制转换

到目前为止,第三种变体似乎是我唯一的选择,而且不是很好的选择。

我认为你的第三种方式可能是最好的选择。毫无疑问,您必须采取一些措施来限制可能的误用

您还可以查看非循环访问者模式:


对于某些场景,Andrei Alexandrescu提供的实现方式(可以推荐他的相关书籍)对我帮助很大。它需要一些努力来充分理解,有点侵入,据我所知,在这里至少不存在100%个宏免费,至少对于C++ 14来说是这样的,但是它在这里可能需要分散的巨大优势。此外,它的次要动态转换使用(不被误用为动态开关)对于大多数用例和现代体系结构来说并不是一个真正的问题。

try
是一个关键词。。。不要把它当作一个名字。