使用现代 C++ 重构带有向量的联合成员的嵌套 switch 语句

Refactor nested switch statement on union members with vectors, using modern C++

提问人:Louis Strous 提问时间:11/15/2023 更新时间:11/18/2023 访问量:72

问:

这是使用现代 C++ 重构联合成员的嵌套 switch 语句的后续问题,并将其扩展到向量。如何使用联合成员摆脱嵌套的 switch 语句来实现对向量的二进制操作?我当前的代码(具有很长的历史)类似于std::variant

enum Value_type_id { i, f, d };
union Pointer { int* i; float* f; double* d; };
struct Item { Value_type_id type; Pointer data; size_t element_count; };

// Item::data points at the beginning of a std::vector
// of the appropriate type with the given element_count.

void add(const Item& lhs, const Item& rhs, Item& result)
{
  assert(lhs.element_count == rhs.element_count);
  assert(lhs.element_count == result.element_count);
  // the type of the data values accessible through
  // "result" is the highest of the types of the data
  // values accessible through "lhs" and "rhs".
  auto n = lhs.element_count;
  auto lhsdata = lhs.data;
  auto rhsdata = rhs.data;
  auto resultdata = result.data;
  switch (lhs.type)
  {
    case i:
      switch (rhs.type)
      {
        case i:
          while (n--)
            *resultdata.i++ = *lhsdata.i++ + *rhsdata.i++;
          break;
        case f:         
          while (n--)
            *resultdata.f++ = *lhsdata.i++ + *rhsdata.f++;
          break;
        case d:
          while (n--)
            *resultdata.d++ = *lhsdata.i++ + *rhsdata.d++;
          break;
      }
      break;
    case f:
      switch (rhs.type)
      {
        case i:         
          while (n--)
            *resultdata.f++ = *lhsdata.f++ + *rhsdata.i++;
          break;
        case f:
          while (n--)
            *resultdata.f++ = *lhsdata.f++ + *rhsdata.f++;
          break;
        case d:
          while (n--)
            *resultdata.d++ = *lhsdata.f++ + *rhsdata.d++;
          break;
      }
      break;
    case d:
      switch (rhs.type)
      {
        case i:         
          while (n--)
            *resultdata.d++ = *lhsdata.d++ + *rhsdata.i++;
          break;
        case f:
          while (n--)
            *resultdata.d++ = *lhsdata.d++ + *rhsdata.f++;
          break;
        case d:
          while (n--)
            *resultdata.d++ = *lhsdata.d++ + *rhsdata.d++;
          break;
      }
      break;
  }
}

这有许多几乎相同的代码副本,仅在使用哪个工会成员方面有所不同。我希望能够做类似的事情

using Data = std::variant<std::vector<int>, std::vector<float>, std::vector<double>>;

Data add(const Data& lhs, const Data& rhs)
{
  return some_magic_here(std::plus(){}, lhs, rhs);
}

但不知道如何让它工作。

C++ 向量 嵌套 switch-statement

评论

0赞 Pepijn Kramer 11/15/2023
看一看 std::visit
0赞 Louis Strous 11/15/2023
我有。我不知道如何在这里应用它。我将不胜感激一个例子。
0赞 Pepijn Kramer 11/15/2023
你试过了吗?我认为这更有意义。using Data = std::vector<std::variant<int*,float*,double*>>
0赞 Andrej Podzimek 11/15/2023
当我从字面上复制和粘贴文档页面时,我得到了这样的东西。如果需要,某些版本很容易添加。另一个有趣的选择是 lambda 中带有参数,这可以使它像 .这一切都是关于在 .const *auto *FunctionalStyleVisitorSimpleVisitoroperator ()(Type)Typestd::variant
1赞 Sam Varshavchik 11/15/2023
不幸的是,Stackoverflow 不是 C++ 帮助站点或教程站点,我们只回答特定问题。如果你想学习如何使用,它是如何工作的,以及如何使用它,一本涵盖高级C++的好C++教科书将是你获取更多信息的最佳资源。如果您对教科书解释中的某些特定内容有任何疑问,可以在此处提问并提供简短的引用或片段。学习 C++ 需要很多时间,C++ 没有即时的满足感。std::variant

答:

0赞 Louis Strous 11/18/2023 #1

一个朋友想出了

Data add(const Data& lhs, const Data& rhs)
 {
   return std::visit([](auto lhsv, auto rhsv)
   {
     using AddType = decltype(lhsv[0] + rhsv[0]);
     auto count = std::min(lhsv.size(), rhsv.size());
     std::vector<AddType> result(count);
     auto lhsp = lhsv.data();
     auto rhsp = rhsv.data();
     auto p = result.data();
     for (int i = 0; i < element_count; i++)
       *p++ = *lhsp++ + *rhsp++;
     return result;
   }, lhs, rhs);
}

这大大减少了代码量。它仍然具有硬编码的二进制操作(此处为加法),但已经是对原始代码的巨大改进。