2

I am trying to sort a member variable type std::list using a local function. Since C++ doesn't allow local functions and hence Herb Sutter's suggests local classes, I ended up with the following code. But am not sure how I can pass a function pointer to the std::list::sort() function.

void MyClass::UpdateList()
  std::map<ClassA*, int> myCustomOrder; //contains order for ClassA objects
  class CompareMyClass
  {
  public:
    CompareMyClass(std::map<ClassA*, int>* order) : m_order(order) { }
    bool operator()(ClassA *p1, ClassA *p2) {
      return m_order->find(p1) < m_order->find(p2);
      return false;
    }
  private:
    std::map<ClassA*, int>* m_order;
  };

  CompareMyClass compareObj(&myCustomOrder); // set the order
  // sort the list
  m_list.sort(compareObj); // How do I pass a function pointer at this point

}

I get a compiler error

a template argument may not reference a local type

Thanks

Marius Bancila
  • 16,053
  • 9
  • 49
  • 91
Chenna V
  • 10,185
  • 11
  • 77
  • 104

2 Answers2

0

As juanchopanza noted and as you can see in this question in c++11 this problem no longer exists, so this would probably be the best way to go if it's possible.


If not I came up with a solution that you might be useful in case you have a small amount of types of local classes (e.g comparators and maybe a couple more). I took the example in the previously mentioned SO question and modified it so it'd work under C++03:


#include <iostream>
#include <vector>
#include <algorithm> // std::remove_if
using namespace std;

template <typename T>
class check {
public:
     virtual bool operator()(T x) = 0;
};

template <typename T>
struct cheat {
cheat(check<T> *c)  {_c = c;}
bool operator()(T x) {return _c->operator ()(x);}
check<T> *_c;
};

int main() {

int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> v( array, array+10 );

class even : public check<int>
{
     public:
     virtual bool operator()( int x ) { cout<<"Hi"<<endl; return !( x % 2 ); }
};
even e;

remove_if( v.begin(), v.end(),  cheat<int>(&e)); // no error, prints Hi

return 0;
}

Also at https://ideone.com/HY5bIU (compiled with Wall,pedantic too... )

If for example I'd like to use a lot of unary operators in my code I can create an abstract class so that all my operators would inherit it, and I've created a cheat class which basically there only to aid with calling a local class.


Edit: Another option with a little smaller imprint:

#include <iostream>
#include <vector>
#include <algorithm> // std::remove_if
using namespace std;

template <typename T>
class check {
public:
virtual bool operator()(T x) = 0;

     struct aid{
          aid(check *p){ _c = p;}
          check *_c;
          bool operator()(T x){
         return _c->operator ()(x);
     }
     };

     aid retMe(){
         return aid(this);
     }
};

int main() {

int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> v( array, array+10 );

class even : public check<int>
{
public:
         virtual bool operator()( int x ) { cout<<"Hi"<<endl; return !( x % 2 ); }
};
even e;

remove_if( v.begin(), v.end(), e.retMe()); // no error

return 0;
}

https://ideone.com/6SZ4UH


Here the aid class is hidden inside the abstract class itself, but the idea is the same.

It does add some unnecessary code but on the other hand it's not as grotesque as some hacks may be.

Community
  • 1
  • 1
Scis
  • 2,934
  • 3
  • 23
  • 37
  • Of course moving the class outside of the function solves the problem but I want to keep the scope of this class's API local to the function. – Chenna V May 01 '14 at 15:33
  • @blueskin The class in the second solution is abstract therefore your specific implementation is not exposed to the outside users, e.g the `even` class will be only visible in the main function. The people who'd potentially abuse this sorting can't they know that there might exist some class of this type but why would that bother you if they can't actually use it? – Scis May 01 '14 at 16:15
0

Example code showing operator overloading, a static function (call commented out), and a lambda function (call commented out):

#include <iostream>
#include <list>
#include <string>

class names
{
    struct name_node
    {
        std::string name;
        inline bool operator< (const name_node &rnode)
            {return (this->name < rnode.name);}
        static bool compare_node(const name_node & lnode, const name_node & rnode)
            {return (lnode.name < rnode.name);}
    };

    std::list <name_node> name_list;

public:
    void get_data();
    void sort_data();
    void show_data();
};

void names::get_data()
{
name_node nn;
std::string fruits[5] = { "peach", "cherry", "apple", "plum", "banana" };

    for (size_t i = 0; i < sizeof(fruits) / sizeof(fruits[0]); i++){
        nn.name = fruits[i];
        name_list.push_back(nn);
    }
}     

void names::sort_data()
{
    name_list.sort();
//  name_list.sort(names::name_node::compare_node);
//  name_list.sort([this](const name_node & lnode, const name_node & rnode)
//                  {return (lnode.name < rnode.name);});
}

void names::show_data()
{
std::list<name_node>::iterator it;
    for(it = name_list.begin(); it != name_list.end(); ++it)
        std::cout << (*it).name << std::endl;
};

int main()
{
names n;
    n.get_data();
    n.sort_data();
    n.show_data();
    return 0;
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • well, this is a nested class, the problem with this in my case is MyClass has friend classes and hence they can access this nested class. This is the specific reason I am looking for a nested function, I do not want anything outside the scope of this function to use this sorting code. It's highly possible that new developers start abusing this function if they have access to this local class. – Chenna V May 01 '14 at 15:30
  • The sort function could be made private, but eventually there will need to be some public function that calls that private sort function, so the new developers would be able to access that, or they could just change the source code and change private stuff to public. You'd need to do code reviews to prevent stuff you don't want to happen. – rcgldr May 01 '14 at 17:30