Как вызвать stl::nth_element с функцией-членом внутри этого класса?

Я хочу использовать функцию nth_element со своей собственной функцией сортировки (которая должна иметь доступ к данным объекта) внутри класса. В настоящее время я делаю следующее:

class Foo
{
 public:
   glm::vec3 *points;
   int nmbPoints;

   bool idxPointCompareX(int a, int b);
   void bar();
}

bool Foo::idxPointCompareX(int a, int b)
{return points[a].x < points[b].x;)

void Foo::bar()
{
   stl::vector<int> idxPointList;
   for(int i = 0; i < nmbPoints; i++) idxPointList.push_back(i);  

   stl::nth_element(idxPointList.first(),idxPointList.first()+nmbPoints/2,idxPointList.end(), idxPointCompareX);
}

Конечно, это не сработало, и я получил ошибку: «Должна быть вызвана ссылка на нестатическую функцию-член». После этого я просмотрел ссылку на нестатический член должна быть вызвана функция, Как инициализировать std::function с членом -function? и некоторые другие вопросы здесь. Я понимаю, почему это не сработало, но я не уверен, как это решить.

Может ли кто-нибудь помочь мне и сказать мне, как решить эту проблему?


person DanceIgel    schedule 16.11.2015    source источник


Ответы (3)


Чтобы получить адрес функции-члена, вам нужно использовать правильный синтаксис, то есть &Foo::idxPointCompareX, а не просто idxPointCompareX

Но вам также нужен объект Foo для вызова функции, поэтому вам нужно будет привязать его к нему. Предположительно, вы хотите вызвать его на this, чтобы вы могли использовать std::bind:

using namespace std::placeholders;
stl::nth_element(begin, begin+n, end,
                 std::bind(&Foo::idxPointCompareX, this, _1, _2));

Или проще, используйте лямбда-функцию:

stl::nth_element(begin, begin+n, end, 
                 [this](int a, int b) { return idxPointCompareX(a, b);}
);

Это создает лямбда-функцию, которая захватывает this и передает свои аргументы функции idxPointCompareX для захваченного указателя this.

person Jonathan Wakely    schedule 16.11.2015
comment
Как я уже упоминал в его ответе, я допустил ошибку при написании вопроса. idxPointCompareX использует индекс для получения доступа к точечным данным «точек». - person DanceIgel; 16.11.2015
comment
здесь вам не хватает n-го элемента. stl::nth_element(begin, begin + smth, end, [this](int a, int b) { return idxPointCompareX(a, b);} ); - person Алексей Неудачи&; 30.07.2020

idxPointCompareX — это функция-член, т. е. ее нельзя вызывать без какой-либо ссылки на объект Foo. Однако, глядя на его определение, кажется, что он не должен быть членом, поскольку он определяется исключительно с точки зрения его аргументов.

Вы можете сделать это функцией static (то есть «функцией класса») или бесплатной функцией, а затем передать ее std::nth_element.

person Frerich Raabe    schedule 16.11.2015
comment
Прошу прощения, что ошибся в вопросе. Я отредактирую его сразу после публикации. - person DanceIgel; 16.11.2015

Вы не можете вызвать метод объекта до его создания, поэтому здесь у вас есть несколько вариантов:

  1. Сделать метод статическим

  2. Оставьте конструктор пустым и переместите все в метод init, где вы вызываете часть сравнения

  3. Используйте лямбду

Примеры:

Статический метод:

static bool idxPointCompareX(glm::vec3 a, glm::vec3 b)
{return a.x < b.x;)

Метод инициализации:

Foo::bar()
{
   stl::vector<int> idxPointList;
   for (int i = 0; i < nmbPoints; i++)
       idxPointList.push_back(i);  
}

Foo::init()
{
    stl::nth_element(idxPointList.first(),
                     idxPointList.first()+nmbPoints/2,idxPointList.end(),
                     idxPointCompareX);
}

Лямбда:

Foo::bar()
{
   stl::vector<int> idxPointList;
   for (int i = 0; i < nmbPoints; i++)
       idxPointList.push_back(i);  

   stl::nth_element(idxPointList.first(),
                    idxPointList.first()+nmbPoints/2,idxPointList.end(),
                    [](int a, int b){return points[a].x < points[b].x;));
}

Я бы сам взял лямбда-версию.

person Netwave    schedule 16.11.2015