STD::p空中任务与下垂
std::pair assignment with downcast
对于事件反应器和促器中的超时,我使用优先级队列,该队列还允许 O(log(n)) 随机访问删除事件(当事件发出信号/完成而不是发生超时时)。我存储std::pair<std::chrono::steady_clock::time_point, Timed *>
其中Timed
是一个类,该类添加具有索引(指向队列),以便在调用TimedQ::Remove(Timed *p)
时允许有效删除。当我想有一个与超时关联的事件类型时,我从Timed
派生。队列的Top()
和Pop()
返回一对。
我曾经有一堆使用队列的代码,例如
std::tie(timePt0, eventPtr0) = timeoutQ.Pop();
std::tie(timePt1, eventPtr1) = std::move(hold);
在我开始使用队列中的基类Timed *
而不是特定事件类型(即 Timed
最初是一个模板化类型),因为我最终需要支持可以与超时关联的多个不同事件类型。但是,由于eventPtr*
是一个派生类型(我可以从队列返回的Timed *
中static_cast
),因此上述代码不再有效。
我想知道最好的方法是什么。现在,它最终变得非常冗长,我担心像临时一样的效率也被创造出来:
auto v(timeoutQ.Pop());
timePt0 = v.first;
eventPtr0 = static_cast<TimedEvent *>(v.second);
std::tie(timePt1, eventPtr1) = std::move(std::make_pair(hold.first, static_cast<TimedEvent *>(hold.second)); // I didn't literally do it like this, but I'm just trying to illustrate my struggle
我唯一的另一个想法是模板化通过派生的事件类返回一对的函数,但从代码大小的角度来看,这似乎很糟糕,因为即使机器代码应该相同,也会创建这些函数的多个实例,因为在所有情况下它都是存储的指针。
编辑:我也尝试使用它,它可以编译,但我不确定是否正确或有效:
template<class D>
std::pair<std::chrono::steady_clock::time_point, D *> &&Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed *> &&in)
{
return std::make_pair(in.first, static_cast<D *>(in.second));
}
然后,最初的例子将成为
std::tie(timePt0, eventPtr0) = Cnvrt<std::remove_pointer<decltype(eventPtr0)>::type>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<std::remove_pointer<decltype(eventPtr1)>::type>(hold);
您显示的Cnvrt
返回一个悬而未决的引用 - 经典 UB。
下面是更正的符合 C++11 的版本,它还在编译时验证D
,并消除了在调用站点进行手动std::remove_pointer<...>::type
的需要:
template<typename D>
constexpr
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) noexcept
{
static_assert(std::is_pointer<D>{}, "D is not a pointer type");
using derived_type = typename std::remove_pointer<D>::type;
static_assert(std::is_base_of<Timed, derived_type>{}, "D does not derive from Timed");
using ptr_type = typename std::remove_cv<D>::type;
return {in.first, static_cast<ptr_type>(in.second)};
}
// ...
std::tie(timePt0, eventPtr0) = Cnvrt<decltype(eventPtr0)>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<decltype(eventPtr1)>(hold);
在线演示
下面是一个应该在 VC++ 2012 上运行的实现:
template<typename D>
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) throw()
{
static_assert(std::is_pointer<D>::value, "D is not a pointer type");
typedef typename std::remove_pointer<D>::type derived_type;
static_assert(std::is_base_of<Timed, derived_type>::value, "D does not derive from Timed");
typedef typename std::remove_cv<D>::type ptr_type;
return std::make_pair(in.first, static_cast<ptr_type>(in.second));
}
在线演示
这里没有任何效率问题 - 即使是最坏的情况,如果编译器根本不进行优化,也只是一个标量和一个指针的副本(VC++ 2012 可能会复制每个副本两次,但同样,只是没有启用优化)。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 如何从 std::async 任务返回 std::tuple
- std 库中是否有类/模板可以在超出范围时执行任务
- 发出std::async任务完成的信号
- STD::p空中任务与下垂
- 对小型任务多次使用std::async是否性能友好