Class with array of pointer to member functions

Dear Root experts,
I have the following problem: I have a class that load a TChain and then loop on the entries executing a function for every entry; the function has a defined signature and is a private non-static member of the class.
Since I have many of these functions, I thought of doing an array of pointer to member functions and using an enumeration to index the function I want to be used.

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>

#include <TMath.h>
#include <TString.h>
#include <TChain.h>
#include <TFile.h>

using namespace std;

class DataSet;

typedef bool (DataSet::* SelectionFunc)();

class DataSet
{
public:
   // Event
   UInt_t  RunID;   // Run number
   UInt_t  EventID; // Event number

   enum selections_t
   {
      SEL1,
      nSELECTIONs
   };

   SelectionFunc Selections[nSELECTIONs];

   DataSet(const Char_t *filename, const Char_t *treename) : chain(NULL)
   {
      initialize_selections_ptrs();
      load_chain(filename, treename);
   }

   ~DataSet()
   {
      if (chain != NULL) delete chain;
   }

   bool CreateEventList(UInt_t selection, Char_t *filename)
   {
      Long64_t selected = 0;
      ofstream file;
      file.open(filename);

      if (file.is_open())
      {
         for (Long64_t ientry = 0; ientry < entries; ++ientry)
         {
            chain->GetEntry(ientry);

            if ((this->*Selections[selection])(this))
            {
               ++selected;
               file << RunID << " " << EventID << endl;
            }
         }

         file.close();

         cout << Form("Selected %lld events (%g%%)\n", selected, (Double_t)selected/entries*100.);

         return true;
      }
      else
      {
         cout << Form("Error in opening file: %s\n", filename);
         return false;
      }
   }

   TChain *chain;
   Long64_t entries;

private:
   bool sel1();

   void initialize_selections_ptrs()
   {
      SelectionFunc selections[nSELECTIONs] = {
         &DataSet::sel1
      };

      for (UInt_t iselection = 0; iselection < nSELECTIONs; ++iselection)
         Selections[iselection] = selections[iselection];
   }

   void load_chain(const Char_t *filename, const Char_t *treename)
   {
      chain = new TChain(treename);
      chain->Add(filename);

      entries = chain->GetEntries();

      cout << Form("Loaded '%s:/%s': %lld entries\n", filename, treename, entries);

      chain->SetBranchAddress("RunID", &RunID);
      chain->SetBranchAddress("EventID", &EventID);
   }
};

bool DataSet::sel1()
{
   return true;
}

It doesn’t work: if I try to compile it (.L DataSet.C+), cint says

DataSet_C_ACLiC_dict.cxx:138: error: declaration of ‘Selections’ as array of void
DataSet_C_ACLiC_dict.cxx: In function ‘void ROOT::DataSet_ShowMembers(void*, TMemberInspector&)’:
DataSet_C_ACLiC_dict.cxx:279: error: ‘class ROOT::Shadow::DataSet’ has no member named ‘Selections’

To make it work, I had to declare the functions external to the class and pass them a pointer to the instance of DataSet, but in this way I cannot use private members.
Am I using pointer to member function in the wrong way?

Hi,

You will need to mark the array of pointer to member function as transient and/or hide it from Cint.

Cheers,
Philippe.

Thanks pcanal, but I have no idea of how to do what you’re suggesting :smiley:

class UserClass { int fNormalDataMember; #ifndef__ CINT__ TypeHardForCINT fUnusualDataMember; #endif .... ClassDef(UserClass,2); };would hide fUnusualDataMember from CINT (note that you need to use add the ClassDef macro to your class if not already there.

class UserClass { int fNormalDataMember; TypeHardForCINT fUnusualDataMember; //! The exclamation mark tell ROOT that this data member is transient. .... };

Cheers,
Philippe.

Does this mean that I won’t be able to use that data member in a program compiled with CINT?

Hi,

Yes, you would not be able to ‘access’ directly this data member from the CINT prompt … but then again even if you did you could not set it or use it (at least not easily) correctly as the function pointer in CINT are a bit different from the real C++ function pointer … However the compile code will still use it properly even from other member function that triggered from the command line.

Cheers,
Philippe.

Ok, thanks pcanal; I think I’ll stick with external functions, since I use mostly CINT.