Вопрос

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

Это было полезно?

Решение

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;
}

Другие советы

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top