Generalizing std::minmax_element In the following answer, @Incomputable basically dared me to implement a generalization of std::minmax_element.


  Have you thought about creating a search function that finds N elements based on N predicates, and return an std::array with the iterators to found elements? I just believe that std::minmax_element can be generalized.


I'm happy to oblige:

#include &lt;array&gt;

template&lt;typename IteT, typename... PredsT&gt;
auto multi_search_elements(IteT begin, IteT end, PredsT const&amp;... preds) {
    const std::size_t count = sizeof...(PredsT);
    std::array&lt;IteT, count&gt; selected;

    selected.fill(begin);
    if(begin != end) {
      for(++begin; begin != end; ++begin) {
        std::size_t i = 0;
        ( (selected[i] = preds(*selected[i], *begin) ? selected[i] : begin, 
           ++i), ...);
      }
    }

  return selected;
}


Usage:

#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;functional&gt;

int main() {
  std::vector&lt;int&gt; vals = {1,2,3,4,5};

  auto found = multi_search_elements(vals.begin(), vals.end(), std::less&lt;int&gt;(), std::greater&lt;int&gt;());

  for(auto i : found) {
    std::cout &lt;&lt; *i &lt;&lt; std::endl;
  }
  return 0;
}


Edit: I understand this fold expression might look like voodoo to people who are not used to that type of code, so I'll elaborate on what's going on here for those of you who are curious:

The fold expression looks like this: (EXPR, ...), which will expand to EXPR, EXPR, EXPR, etc..., where the "binary" operator used is actually the comma operator, which effectively just sequences the expressions while leaving them unrelated. 

After that, all I do is make EXPR be SUB_EXPR, ++i, so the whole thing expands as:

(SUB_EXPR, ++i), (SUB_EXPR, ++i), (SUB_EXPR, ++i), (SUB_EXPR, ++i), ...


Which is essentially:

selected[i] = preds_0(*selected[i], *begin) ? selected[i] : begin,
++i,
selected[i] = preds_1(*selected[i], *begin) ? selected[i] : begin,
++i,
selected[i] = preds_2(*selected[i], *begin) ? selected[i] : begin,
++i,
selected[i] = preds_3(*selected[i], *begin) ? selected[i] : begin,
++i
This code is pretty good, and there's very little to improve.  The two-line fold expression did benefit from the explanatory comment in the description, so perhaps it could get a summary in the code?

I found a couple of very minor simplifications:


We can declare count as

    static const auto count = sizeof...(PredsT);

Instead of duplicating ++begin in a for loop, we can transform to a simpler while loop:

    while (++begin != end) {

Instead of indexing selected, we might choose to iterate (and avoid a no-op assignment, and avoid the need to remember precedence of comma operator):

    auto p = selected.begin();
    ((preds(**p, *begin) ? *p++ : *p++ = begin), ...);