C++17 std::variant 比动态多态性慢?

Posted

技术标签:

【中文标题】C++17 std::variant 比动态多态性慢?【英文标题】:C++17 std::variant is slower than dynamic polymorphism? 【发布时间】:2021-10-05 03:37:46 【问题描述】:

我正在关注this blog,并试图将动态多态代码替换为使用std::variantstd::visit。但我无法让std::variant + std::visit 比虚拟结构 impl 工作得更好。它大约 慢了 1.3-1.5 倍! (GCC 10.3 -O3 C++17)

用例如下。假设我们正在比较两个表的第 i 行和第 j 行。表可能具有异构类型的列。假设我们可以访问列缓冲区。 我正在做的是测试,

def IndexEqual(Table:A, Table:B, int:i, int:j):
  for c in range(A.num_cols):
     if not A.column(c)[i] == B.column(c)[j]:
         return False
  return True

对于动态多态性,我有以下intfloat

struct Comp
  virtual bool comp(size_t i, size_t j) const = 0;
;

struct CompI: public Comp 
  CompI(const int *data_1, const int *data_2) : data1(data_1), data2(data_2) 

  const int *data1, *data2;
  bool comp(size_t i, size_t j) const override 
    return data1[i] == data2[j];
  
;

struct CompF: public Comp 
  CompF(const float *data_1, const float *data_2) : data1(data_1), data2(data_2) 

  const float *data1, *data2;
  bool comp(size_t i, size_t j) const override 
    return data1[i] == data2[j];
  
;

bool IndexEqual1(const std::vector<Comp *> &comps, size_t i, size_t j) 
  for (auto &&a: comps) 
    if (!a->comp(i, j)) 
      return false;
    
  
  return true;

这被转换为std::variant + std::visit,如下所示。

struct EqualToI 
  EqualToI(const int *data_1, const int *data_2) : data1(data_1), data2(data_2) 
  const int *data1, *data2;
  bool comp(size_t i, size_t j) const 
    return data1[i] == data2[j];
  
;

struct EqualToF 
  EqualToF(const float *data_1, const float *data_2) : data1(data_1), data2(data_2) 
  const float *data1, *data2;
  bool comp(size_t i, size_t j) const 
    return data1[i] == data2[j];
  
;

using var_type = typename std::variant<EqualToI, EqualToF>;

bool IndexEqual(const std::vector<var_type> &comps, size_t i, size_t j) 
  for (auto &&a: comps) 
    if (!std::visit([&](const auto &comp) 
      return comp.comp(i, j);
    , a)) 
      return false;
    
  
  return true;

我在这里进行了基准测试 https://quick-bench.com/q/u-cBjg4hyQjOs6fKem9XSdW7LMs

谁能解释一下为什么这个std::variant + std::visit 选项比动态多态方法慢?我的预期不是这样!我的方法和/或基准有问题吗?

【问题讨论】:

您关注的那个博客不是在描述静态多态性。试试这个博客:mropert.github.io/2017/11/30/polymorphic_ducks std::variant有两种实现方式,动态调度和魔术。 【参考方案1】:

使用variant 不构成“静态多态”。它仍然是动态多态性,因为编译器不知道哪种类型将实际存在于variant 中。因此,有问题的代码必须尝试找出 variant 在运行时存储的内容,并且必须相应地调度这些调用。

请注意,您链接到的文章并未将其称为“静态多态性”。它强调它只是与虚函数不同形式的“运行时多态性”。

【讨论】:

我明白了。感谢您的澄清(我相应地更改了标题)。有没有更好的方法可以实现这一目标? @n1r44 所以你想要一个比所有已知的更快的动态调度实现,对吧? @n1r44 当然只是手动滚动您自己的动态调度。向下移动多态性,删除一两个间接级别。然后针对真实数据进行数周的分析和调整。

以上是关于C++17 std::variant 比动态多态性慢?的主要内容,如果未能解决你的问题,请参考以下文章

C++17,制作一个使用依赖于模板参数的 std::variant 的可变参数模板?

与传统的多态处理相比,使用 std::variant 有啥优势?

在 std::variant 中使用不完整类型

C++17好用的类

将 std::unique_ptr 的子类与 std::variant 一起使用

C ++中的变体变体