tags:

views:

262

answers:

5

I am trying to combine the following two functions into one portable function:

void NeedleUSsim::FindIdxRho()
{
    searchTmp = &ninfo->rho;
    double *p = std::find_if(tplRho_deg, tplRho_deg+sampleDim[2], &NeedleUSsim::GreaterThanOrEqualTo);
    while(p != tplRho_deg+sampleDim[2])
    {
     idxRho = p - tplRho_deg;
     p = std::find_if(p+1, tplRho_deg+sampleDim[2], &NeedleUSsim::GreaterThanOrEqualTo);
    }
}

void NeedleUSsim::FindIdxDepth()
{
    searchTmp = &ninfo->l;
    double *p = std::find_if(tplL, tplL+sampleDim[1], &NeedleUSsim::LessThanOrEqualTo);
    while(p != tplL+sampleDim[1])
    {
     idxL = p - tplL;
     p = std::find_if(p+1, tplL+sampleDim[1], &NeedleUSsim::LessThanOrEqualTo);
    }
}

Ideally, I want the parameters of the function to have tpl member to be passed as a pointer, with the size and rho/l passed as value. searchTmp is a file scope double precision pointer. Is there any easy way of passing &NeedleUSsim::GreaterThanOrEqualTo function as a parameter of the function that I'm trying to write easily?

Thanks in advance for the advice.

+1  A: 

It is possible to pass a member function pointer to a function as follows:

typedef bool (NeedleUSsim::*compFunctionPtr)(NeedleUSsim &x, NeedleUSsim &y);

void NeedleUSsim::FindIdxRho(compFunctionPtr comparison)
{
    //..
    p = std::find_if(tplRho_deg, tplRho_deg+sampleDim[2], comparison);
    //..
}

Which can then be called like so:

//..
someNeedleUSsim.FindIdxRho(&NeedleUSsim::LessThanOrEqualTo);
//..

Have a look at this C++ FAQ Lite article for more information.

e.James
+3  A: 

Is there any easy way of passing &NeedleUSsim::GreaterThanOrEqualTo function as a parameter of the function that I'm trying to write easily?

There's a couple ways to do this.

  1. You can pass the function pointer around
  2. You can create and pass a function object using run-time polymorphism
  3. You can make your common function templated on a function object (compile time polymorphism)

The first method is covered above by eJames.

Option 2

The second method involves wrapping your comparison functions in some function-object hierarchy. A function object is an instance of a class with the () operator overloaded. This makes the instance callable:

 class IComparator
 {
 public:
    virtual bool operator()(lhs, rhs) = 0;
 }


 class CComparatorLessThan : public IComparator
 {
 public:
    virtual bool operator()(lhs, rhs) {...}
 }


 class CComparatorGreaterThan : public IComparator
 {
 public:
    virtual bool operator()(lhs, rhs) {...}
 }

Your common function would take an ICompatator reference and the behavior would be dynamically bound at runtime.

Option 3

The third method involves templatizing instead of creating an object hierarchy

template <class Comparator>
void foo(...)
{
   ...
   Comparator comparer;
   std::find_if(..., comparer);
}

then calling foo would involve:

foo<CComparatorGreaterThan>(...);

This eliminates a lot of the runtime overhead of the second solution. Here you don't have to define the base class. You only have to have some kind of class that has operator() overloaded and will return bool.

Doug T.
Eclipse
+1  A: 

The easy way to take functions and more complex parameters into a function is to template them (I'm guessing at some of the parameter types)

template <typename F>
void NeedleUSsim::FindIdx(double *ninfoMember, double *tplParam, size_t dimension, F CompareFunc, int &target)
{
    searchTmp = ninfoMember;
    double *p = std::find_if(tplParam, tplParam+sampleDim[dimension], CompareFunc);
    while(p != tplParam+sampleDim[dimension])
    {
        target= p - tplParam;
        p = std::find_if(p+1, tplParam+sampleDim[dimension], CompareFunc);
    }
}

Then call it:

FindIdx(&ninfo->rho, tplRho_deg, 2, &NeedleUSsim::GreaterThanOrEqualTo, idxRho);
FindIdx(&ninfo->l, tplL, 1, &NeedleUSsim::LessThanOrEqualTo, idxL);
Eclipse
+5  A: 

The simplest way to make your code a bit more generic is the following :

template<typename ComparisonType>
double* NeedleUSsim::FindIdx(double* containerBegin, double* containerEnd, ComparisonType comparison) {
    double* p = std::find_if(containerBegin, containerEnd, comparison);
    double* idx = 0;
    while(p != containerEnd)
    {
        idx = p - containerBegin;
        p = std::find_if(p+1, containerEnd, comparison);
    }
    return idx;
}

void NeedleUSsim::FindIdxRho()
{
  searchTmp = &ninfo->rho;
  double* idx = FindIdx(tplRho_deg, tplRho_deg+sampleDim[2], &NeedleUSsim::GreaterThanOrEqualTo);
  if( idx != 0 )
  {
    idxL = idx;
  }

}

void NeedleUSsim::FindIdxDepth()
{
  searchTmp = &ninfo->l;
  double* idx = FindIdx(tplL, tplL+sampleDim[1], &NeedleUSsim::LessThanOrEqualTo);
  if( idx != 0 )
  {
    idxRho = idx;
  }
}
Benoît
Should there be a "searchTmp = " in the first line of the FindIdx function?
stanigator
Sorry, you're right.
Benoît
Also, you should probably do something with idxL = ...
Eclipse
Right again. Corrected !
Benoît
Would it be better if idx is an integer stating the index rather than having the FindIdx returning a pointer (i.e. return an int rather than a pointer to a double?)?
stanigator
Clearly, yes. Divide p2-p1 by sizeof(double).
Benoît
There is a hidden difference between your code and the questioner's one. if the questioner's one doesn't find the item, idxRho and idxL won't be written to. This one will always write to them. That may be important and too easy to overlook.
Johannes Schaub - litb
You are absolutely right. I'll update my code.
Benoît
+1  A: 
double *p = std::find_if(b, e, &NeedleUSsim::GreaterThanOrEqualTo);
while(p != e)
{
    idxRho = p - b;
    p = std::find_if(p + 1, e, &NeedleUSsim::GreaterThanOrEqualTo);
}

Note that this loop that you use is not necessary. Use reverse iterators

std::reverse_iterator<double*> rb(e), re(b);
rb = std::find_if(rb, re, &NeedleUSsim::GreaterThanOrEqualTo);
if(rb != re) {
    idxRho = re - rb;
}

Now its more obvious what it does. If writing to idxRho only when something was found was a mistake or doesn't matter, you can shorten it to this

std::reverse_iterator<double*> rb(e), re(b);
idxRho = re - std::find_if(rb, re, &NeedleUSsim::GreaterThanOrEqualTo);
Johannes Schaub - litb