Как да извикам 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 с член -функция? и някои други въпроси тук. Разбирам защо това не проработи, но не съм сигурен как да разреша това.

Може ли някой да ми помогне и да ми каже как да реша този проблем?


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