c++ - std::pair assignment with downcast

标签 c++ c++11 move std-pair argument-unpacking

对于事件 react 器和前导器中的超时,我使用了一个优先级队列,它还允许 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* 是派生类型(我可以从 static_cast 到队列返回的 Timed *),上面的代码不再有效。

我想知道执行此操作的最佳方法是什么。现在,它最终变得非常冗长,而且我还担心创建临时文件等效率问题:

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);

Online Demo

这是一个应该在 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));
}

Online Demo

这里没有任何效率问题——即使是您的最坏场景,如果编译器根本不进行优化,也只是一个标量和一个指针的拷贝(VC++ 2012 可能会复制每个两次,但同样,只是没有启用优化)。

关于c++ - std::pair assignment with downcast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35054983/

相关文章:

c++ - 如何使用 QProcess 中的 bash 命令 'which'

c++ - 使用参数绑定(bind)通用回调 c++11

c++ - 使用 g++ 4.8.2 时,tan() 计算比 sin()/cos() 长两倍

c++ - 为什么 move vector 和 move 元素对 vector 的大小有不同的影响?

c++ - 提高 mmap memcpy 文件读取性能

c++ - 如何将带有双反斜杠的字符串转换为单反斜杠

c++ - CreateProcessAsUser和createevent权限

c++ - 无法使用 std::end 打印字符串

c# - 如何使用 WinApi 随心所欲地 move 窗口

javascript - Jquery - 根据条件向左或向右 move 元素