Home | News | Documentation | Download

STL UnaryPredicates with TCollection

Does ROOT not support STL’s UnaryPredicates, or am I doing something wrong? Thanks for your help!

root [0] TObjArray *arr = new TObjArray()
root [1] all_of(arr->begin(), arr->end(), [](TObject *obj) { return true; })
In module 'std' imported from input_line_1:1:
/usr/include/c++/9/bits/stl_algo.h:173:8: error: no matching function for call to '__iterator_category'
                            std::__iterator_category(__first));
                            ^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/9/bits/stl_algo.h:566:19: note: in instantiation of function template specialization 'std::__find_if_not<TIter, __gnu_cxx::__ops::_Iter_pred<(lambda at
      ROOT_prompt_1:1:34)> >' requested here
      return std::__find_if_not(__first, __last,
                  ^
/usr/include/c++/9/bits/stl_algo.h:509:29: note: in instantiation of function template specialization 'std::find_if_not<TIter, (lambda at ROOT_prompt_1:1:34)>' requested here
    { return __last == std::find_if_not(__first, __last, __pred); }
                            ^
ROOT_prompt_1:1:1: note: in instantiation of function template specialization 'std::all_of<TIter, (lambda at ROOT_prompt_1:1:34)>' requested here
all_of(arr->begin(), arr->end(), [](TObject *obj) { return true; })
^
/usr/include/c++/9/bits/stl_iterator_base_types.h:205:5: note: candidate template ignored: substitution failure [with _Iter = TIter]: no type named 'iterator_category' in
      'std::iterator_traits<TIter>'
    __iterator_category(const _Iter&)
    ^

It does work on some platforms and not others. It looks like the C++ std libraries you are using here as “additional/new” requirements for containers that we are not yet added (it seems to be that we are missing std::iterator_traits<TIter>)

If you can not switch to std::vector. You can use this work around for TObjArray:

(arr->GetEntries()>0) && all_of(&((*arr)[0]), &((*arr)[arr->GetEntries()-1]), [](TObject *obj) { return true; })

Thanks, but I guess that will not check for the last element. There are definitely cleaner ways to test this but this is the first thing that came to my mind:

root [0] TObjArray *arr = new TObjArray()
root [1] (*arr)[0] = new TH1F("h", "", 1, 0, 1)
root [2] (*arr)[1] = new TH1F("g", "", 1, 0, 1)
root [3] (arr->GetEntries()>0) && all_of(&((*arr)[0]), &((*arr)[arr->GetEntries()-1]), [](TObject *obj) { return obj->GetName() == TString("h"); })
(bool) true
 

This sounds like a good candidate for a bug report at Issues · root-project/root · GitHub – however as Philippe mentioned we typically suggest to switch to STL containers if possible.

Cheers,
Enrico

In my specific case it is not my code, so it’s not possible to use STL containers for me.

I can file a bug report, but probably I don’t have the necessary knowledge to understand precisely what is the bug there…

In the meantime as a workaround I wrote my own function:

#include <functional>

bool all_of(TCollection *collection, const std::function<bool(TObject *)> &predicate)
{
  bool result = true;
  for (auto object : *collection)
    if (!predicate(object)) {
      result = false;
      break;
    }
  return result;
}

Oups :innocent:, simple off by one error:

(arr->GetEntries()>0) && all_of(&((*arr)[0]), &((*arr)[arr->GetEntries()]), [](TObject *obj) { return obj->GetName() == TString("h"); })
(bool) false