22.8 Composition Functors in OEChem

Occasionally, one may want to use a logical operator to join two or more functors. While it is certainly possible to write a quick functor which wraps two or more functors, with the "magic" of templates this is not necessary. The functors OEAnd, OEOr and OENot are already defined. The each have constructors which take the appropriate number of predicates as arguments and generate a single unary predicate. Often these functors can be constructed inline.

The following example demonstrates use of the OEAnd and OENot composition predicates with two of the predefined atom predicates

#include "oechem.h"
#include "oesystem.h"

#include <iostream>

using namespace OESystem;
using namespace OEChem;
using namespace std;

unsigned int Count(const OEUnaryPredicate<OEAtomBase> &fcn,
                   const OEMolBase &mol)
{
  unsigned int count = 0;
  OEIter<OEAtomBase> atom;
  for(atom = mol.GetAtoms();atom;++atom)
    if(fcn(*atom))
      ++count;

  return count;
}

int main()
{
  OEGraphMol mol;
  OEParseSmiles(mol, "c1c(O)c(O)c(Cl)cc1CCCBr");

  cerr << "Number of Aromatic Oxygens = " <<
          Count(OEAnd<OEAtomBase>(OEIsOxygen(),OEIsAromaticAtom()),mol) << endl;

  cerr << "Number of Non-Carbons = " <<
          Count(OENot<OEAtomBase>(OEHasAtomicNum(6)),mol) << endl;

  return 0;
}

The example above is an extension of listing 18.2 above. It shows the use of OEChem's composition functors to build expressions from OEChem's predefined atom predicates. Thought the explicit template type instantiation isn't strictly necessary, in practice it is required to help several parsers make it through the expression.

As a convenience to programmers, three related template free functions have been defined. These are operator &&, operator || and operator ! which take one or more OEUnaryPredicates as arguments and return the appropriate composition predicate. Not only do these make code much easier to read, but in our experience, they also make the code easier for C++ parsers to parse.

The following example is identical to the previous composition listing except that the composition predicates have been replaced by the operator free-functions.

#include "oechem.h"
#include "oesystem.h"

#include <iostream>

using namespace OESystem;
using namespace OEChem;
using namespace std;

unsigned int Count(const OEUnaryPredicate<OEAtomBase> &fcn,
                   const OEMolBase &mol)
{
  unsigned int count = 0;
  OEIter<OEAtomBase> atom;
  for(atom = mol.GetAtoms();atom;++atom)
    if(fcn(*atom))
      ++count;

  return count;
}

int main()
{
  OEGraphMol mol;
  OEParseSmiles(mol, "c1c(O)c(O)c(Cl)cc1CCCBr");

  cerr << "Number of Aromatic Oxygens = " <<
          Count(OEIsOxygen() && OEIsAromaticAtom(),mol) << endl;

  cerr << "Number of Non-Carbons = " <<
          Count(!OEHasAtomicNum(6),mol) << endl;

  return 0;
}