0

I give the following example to illustrate my question:

class Abc
{
public:
  int height();
  int width();
  int area();

};

typedef std::vector<class Abc> AbcArray;

void obtain_selected_list_based_on_area(AbcArray& objArray, 
    std::vector<int> &listIndexArray)
{
   std::vector<int> areaArray;
   for(int i=0; i<objArray.size(); i++)
            areaArray.push_back(objArray[i].area());

   function_select_list(areaArray,listIndexArray);
}

void obtain_selected_list_based_on_height(AbcArray& objArray, 
    std::vector<int> &listIndexArray)
{
   std::vector<int> areaArray;
   for(int i=0; i<objArray.size(); i++)
            areaArray.push_back(objArray[i].height());

   function_select_list(areaArray,listIndexArray);
}

void obtain_selected_list_based_on_width(AbcArray& objArray, 
    std::vector<int> &listIndexArray)
{
   std::vector<int> areaArray;
   for(int i=0; i<objArray.size(); i++)
            areaArray.push_back(objArray[i].width());

   function_select_list(areaArray,listIndexArray);
}

As you can see from the above code snippet, we decide to select the list based on three different criteria. In order to do that, we have to write three functions: obtain_selected_list_based_on_area, obtain_selected_list_based_on_height, and obtain_selected_list_based_on_width.
I just wondering how I can simplify it.
For me there one solutions. One is to use function pointer:

void obtain_select_list(AbcArray& objArray, std::vector<int> &listSel, FUN fun)
{
    std::vector<int> areaArray;
       for(int i=0; i<objArray.size(); i++)
                areaArray.push_back(objArray[i].width());

       function_select_list(areaArray,listIndexArray);

}

However, I cannot make it work because the function pointer is pointing to the member of a class.
Do you have some ideas on how to make it work? Moreover, any other solutions for this problem?

skypjack
  • 49,335
  • 19
  • 95
  • 187
feelfree
  • 11,175
  • 20
  • 96
  • 167
  • 1
    You could go all the way over to an IOC solution: instead of passing a function pointer, pass a reference to an instance of a class bearing a suitable method, and have `obtain_select_list()` invoke that method on the instance to do its work. – John Bollinger Dec 16 '16 at 20:57
  • ... also, I'd pass the function as a compile-time (template) parameter. It's way faster to call a known function: a fnptr is about as slow as a virtual call! – lorro Dec 16 '16 at 21:00
  • Off-topic: IMHO, you should be using `unsigned int` for `height`, `width`, and `area`. The `int` type allows for negative numbers. I have yet to see negative heights, widths or areas. – Thomas Matthews Dec 16 '16 at 21:19
  • The question is very broad, allowing a multitude of possible approaches, and it's very vague, e.g. the `function_select_list` is not defined anywhere, there's no context. The simplest approach that preserves generality is probably to pass an ordinary function that retrieves a value from an `Abc`. Other approaches include passing member function pointer, member data pointer, an interface object, a simple selector value, etc. Voted to close as too broad. – Cheers and hth. - Alf Dec 16 '16 at 21:20
  • @ThomasMatthews Be careful, Some [people](http://stackoverflow.com/questions/40945872/finding-the-primary-numbers-in-an-array-of-pointer/40946175#comment69104163_40946175) are not agree. This is a open [question](http://stackoverflow.com/questions/30395205/why-are-unsigned-integers-error-prone). – Stargateur Dec 16 '16 at 22:03

2 Answers2

2

Not exactly function pointers, but rather class method pointers.

Additionally, using C++11 range iteration makes the resulting syntax much simpler, and easier to read:

void obtain_selected_list_based_on(AbcArray& objArray, 
    std::vector<int> &listIndexArray,
    int (Abc::*get_something)())
)
{
   std::vector<int> areaArray;

   for (const auto &v:objArray)
            areaArray.push_back((v.*get_something)());

   function_select_list(areaArray,listIndexArray);
}

This can be invoked as:

obtain_selected_list_based_on(objArray,
                              listIndexArray,
                              &Abc::height);

// or

obtain_selected_list_based_on(objArray,
                              listIndexArray,
                              &Abc::width);

// or

obtain_selected_list_based_on(objArray,
                              listIndexArray,
                              &Abc::area);

Your class methods should probably be const themselves, which would change the parameter type to int (Abc::*get_something)() const.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
0

I think something like this should work.

void <template T> obtain_select_list(AbcArray& objArray, std::vector<int> &listSel, T (*fun)(const Abc&))
{
    std::vector<T> areaArray;
       for(int i=0; i<objArray.size(); i++)
                areaArray.push_back(fun(objArray[i]));

       function_select_list(areaArray,listIndexArray);

}

Just to be more general i used a template one, so that if you need the function to return things different from an int you can still use it.

I wasn't able to test it, it compiles but i don't know it if works, but it should.

bracco23
  • 2,181
  • 10
  • 28