Search code examples
c++c++17fold-expression

C++17 fold syntax to test vector composition


Standard C++17 implementation of vector any, all:

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

for usage as in

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

Is there an analogous way to define only, which returns true if and only if the set of unique values of the vector matches the input values? So the following asserts would hold

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

Solution

  • 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();
    }
    

    this counts how many of the list ts... are in c, and returns true if the number you found ear equal to the elements of c. Now this assumes uniqueness of c and ts.

    We just move the counting into only and test within the std algorithm:

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

    and bob is your uncle.

    We could also do a notcontains based only algorithm, but I think that is more complex.