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

3
  • 1
    Can you try with C++11 support? C++03 doesn't allow local types as template arguments. Commented Apr 30, 2014 at 21:17
  • I do not know, but can std::sort give any ideas? Example here gsamaras.wordpress.com/code/sort-c Commented Apr 30, 2014 at 21:24
  • @juanchopanza: Thanks, C++11 does support this code. Commented May 1, 2014 at 15:34

2 Answers 2

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

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.
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.
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.

2 Comments

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.
@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?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.