【问题标题】:C++17 fold syntax to test vector compositionC++17折叠语法测试向量组合
【发布时间】:2020-09-29 23:35:39
【问题描述】:

向量anyall的标准C++17实现:

template<class C, class T>
bool contains(const C& c, const T& value) {
  return std::find(c.begin(), c.end(), value) != c.end();
}

template<class C, class... T>
bool any(const C& c, T&&... value) {
  return (... || contains(c, value));
}

template<class C, class... T>
bool all(const C& c, T&&... value) {
  return (... && contains(c, value));
}

用于中的用法

std::array<int, 6> data0 = { 4, 6, 8, 10, 12, 14 };
assert( any(data0, 10, 55, 792));
assert( !any(data0, 11));

assert( all(data0, 6, 14, 8));
assert( !all(data0, 6, 7, 8));

是否有类似的方法来定义only,当且仅当向量的唯一值集与输入值匹配时才返回 true?所以以下断言将成立

std::array<int, 6> data1 = { 1, 1, 2, 1, 2 };
assert( only(data1, 1, 2));
assert( !only(data1, 1));

【问题讨论】:

  • 传递给only(参数包)的值是否保证具有唯一值?
  • 我们可以假设是的。
  • 虽然在技术上可能是可行的,但我认为尝试将其作为折叠表达式来做是没有意义的。在 std 库函数中,您提供的要检查的值列表使用折叠表达式扩展为单个值,但如果您的目标是检查唯一性,则需要知道唯一列表的全部范围,因此扩展列表将违反直觉。

标签: c++ c++17 fold-expression


【解决方案1】:

你可以提供一个count函数:

template<class C, class T>
auto count(const C& c, const T& value) {
  return std::count(c.begin(), c.end(), value);
}

并像这样写only

template<class C, class... T>
bool only(const C& c, T&&... value) {
  return (count(c, value) + ...) == c.size();
}

这会处理c 中的重复元素,但要求values 是唯一的。

这是demo

【讨论】:

    【解决方案2】:
    template<class C, class...Ts>
    bool only( C const& c, Ts&&...ts ) {
      std::size_t count = (std::size_t(0) + ... + contains(c, ts));
      return count == c.size();
    }
    

    这会计算c 中有多少列表ts...,如果您找到的数量等于c 的元素,则返回true。现在这假设 cts 的唯一性。

    我们只是将计数移到only 并在标准算法中进行测试:

    template<class C, class...Ts>
    bool only( C const& c, Ts&&...ts ) {
      using std::begin; using std::end;
      auto count = std::count_if( begin(c), end(c), [&](auto&& elem) {
        return ((elem == ts) || ...);
      } );
      return count == c.size();
    }
    

    鲍勃是你的叔叔。

    我们也可以做一个基于notcontainsonly 算法,但我认为这更复杂。

    【讨论】:

      【解决方案3】:

      它不使用折叠表达式,但它应该可以工作

      template<class C, class... T>
      bool only(const C& c, T&& ...vals) {
          auto ilist = {vals...}; //create initializer_list
      
          for (auto el : c) {
              if (!contains(ilist, el)) return false;
          }
          return true;
      }
      

      使用折叠表达式而不是std::initializer_list的东西

      template<class T, class... Ts>
      bool is_one_of(const T& val, Ts&& ...vals)
      {
          return ((val == vals) || ...);
      }
      
      template<class C, class... Ts>
      bool only(const C& c, Ts&& ...vals)
      {
          for (const auto& el : c) {
              if (!is_one_of(el, vals...)) return false;
          }
          return true;
      }
      
      // or if you hate raw loops
      template<class C, class... Ts>
      bool only(const C& c, Ts&& ...vals)
      {
          using std::beign; using std::end;
          auto it = std::find_if(begin(c), end(c), [&](const auto& el) {
              return !is_one_of(el, vals...);
          });
          return (it == end(c));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-29
        • 1970-01-01
        • 2020-02-21
        相关资源
        最近更新 更多