Метод захвата класса в лямбде - PullRequest
0 голосов
/ 22 июня 2019

У меня есть несколько методов в моем классе. Я хочу лямбда в одном методе для вызова другого метода класса. Но я не хочу захватывать this, чтобы ограничить область доступа к лямбде. Это возможно?

Я пытался описать метод как [&method = Class::my_method] или его варианты, но кое-что мне не хватает.

#include <iostream>

class Hello
{
public:

  double test_lambda(const double in)
  {
      // If I capture `this` instead, then this works fine
      const auto a_lambda = [add_number = this->add_number](const double in)
      {
        return add_number(in);  
      };
      return a_lambda(in);
  }

private:

  double add_number(const double in)
  {
      return in + 2.0;
  }

};

int main()
{
    Hello h;
    std::cout << "Hello World: " << h.test_lambda(4.0); // Expect 6
    return 0;
}

Я надеюсь, что смогу запечатлеть такой метод, но я не уверен, что это возможно.

Причина, по которой я хочу сделать это на основе предпочтения кодирования, ограничивающего доступ к лямбде. Например, если бы я хотел, чтобы лямбда видоизменяла членов класса, я мог бы сделать

another_lambda = [this](){
m_value_one = 1.0;
m_value_two = 2.0;
// This has access to other members
}

Или, чтобы ограничить то, что лямбда может мутировать, я могу сделать:

another_lambda = [&value_one = this->m_value_one, &value_two = this->m_value_two](){
value_one = 1.0;
value_two = 2.0;
// This does not have access to other members
}

В посте спрашивается, можно ли сделать то же самое с помощью методов класса, но, похоже, это невозможно.

1 Ответ

1 голос
/ 22 июня 2019

Захват и использование указателя на функцию-член

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

#include <iostream>

class Hello
{
   public:
    double test_lambda(double in)
    {
        auto a_lambda = [add_number = &Hello::add_number, this](double in) {
            // This is how we call a pointer to a member function
            return (this->*add_number)(in);
        };
        return a_lambda(in);
    }

   private:
    double add_number(double in) { return in + 2.0; }
};

int main()
{
    Hello h;
    std::cout << "Hello World: " << h.test_lambda(4.0); // Expect 6
    return 0;
}

Более простое решение - захват по ссылке

Мы можем захватить текущий класс по ссылке, и это позволяет вам использовать add_number без квалификаторов:

#include <iostream>

class Hello
{
   public:
    double test_lambda(double in)
    {
        auto a_lambda = [&](double in) {
            // add_number can be called normally
            return add_number(in);
        };
        return a_lambda(in);
    }

   private:
    double add_number(double in) { return in + 2.0; }
};

int main()
{
    Hello h;
    std::cout << "Hello World: " << h.test_lambda(4.0); // Expect 6
    return 0;
}
...