-1

I have several methods in my class. I want a lambda in one method to call another method of the class. But I don't want to capture this so that I can limit the scope of what the lambda has access to. Is this possible?

I've tried to capture the method as [&method = Class::my_method] or variations of that but there's something I'm missing.

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

I would hope that I could capture a method like this but I'm not sure if it's possible.

The reason I want to do this based on a coding preference to limit what the lambda has access to. For example, if I wanted the lambda to mutate members of a class, I could do

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

Or to limit what the lambda can mutate, I can do:

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
}

The post is asking whether the same can be done with class methods, but it seems that it cannot.

Otto Nahmee
  • 133
  • 1
  • 2
  • 13
  • 1
    Capture a method that gets called on what object? What is the `this` object upon which you want `return add_number(in);` to operate? – Nicol Bolas Jun 21 '19 at 22:02
  • 2
    Possible duplicate of [Pass a class member function as a function parameter](https://stackoverflow.com/questions/7218519/pass-a-class-member-function-as-a-function-parameter) – JaMiT Jun 21 '19 at 22:11
  • Why, for a 1 line lambda, do you care? – Yakk - Adam Nevraumont Jun 22 '19 at 02:14
  • @NicolBolas I think I see the problem here, which is why it works if add_number was static – Otto Nahmee Jun 24 '19 at 15:10
  • @Yakk-AdamNevraumont This was a toy example – Otto Nahmee Jun 24 '19 at 15:10
  • @OttoNahmee And I can give a toy answer to a toy example. I cannot, however, determine what additional features your actual problem is that makes the toy answer not an answer to your real problem. When you have a problem, find what you think is a solution, the solution doesn't work, then you boil the entire problem away until the "solution" would solve some toy problem, the answer can easily be "your problem has no/a simple solution" while **the original problem** isn't solved by it. Even "the lambda has 100 lines of code, how do I ensure it only calls a specific method" would do. – Yakk - Adam Nevraumont Jun 24 '19 at 15:51
  • And no, that isn't obviously your problem. Your problem as stated "I want to capture a method". Solutions to "I want to ensure a 100 line long lambda only calls a specific method" can exist that *don't solve the problem you have asked here*. Do a [MCVE], but the MCVE must be such that either (a) solving the MCVE actually solves your problem (for example, just type `this->add_number(in)` in the body of the lambda, and read it to ensure you didn't type something else), or (b) you describe with the real problem you simplified. – Yakk - Adam Nevraumont Jun 24 '19 at 15:54
  • @Yakk-AdamNevraumont Ah, I see your confusion. I stated that I don't want to capture `this` so that I can limit the scope of what the lambda has access to. That was stated in the question. I should have said I don't want to capture `this` or `&` because I want to limit the scope further. – Otto Nahmee Jun 24 '19 at 18:23
  • You can limit what the lambda has access to by not naming any other methods in the body of the lambda. Capturing `this` doesn't prevent that simple technique. I assume there is something else in your *actual* problem that makes this simple technique impractical, but you don't seem to what to say what it is. For your toy problem, it is by far the most practical solution. It isn't just me; there are 3 people who voted to close your question as being a duplicate of a question which I *suspect* doesn't solve your problem; I cannot be sure, you won't describe your problem. Anyhow, I give up. – Yakk - Adam Nevraumont Jun 24 '19 at 18:26
  • @Yakk-AdamNevraumont You are correct, capturing `this` doesn't prevent that simple technique. I'm in favor of limiting access of lambdas and capturing `this` doesn't prevent that. This is why I am trying to limit scope. – Otto Nahmee Jun 24 '19 at 18:29

1 Answers1

1

Capturing and using a pointer to member function

A member function isn't a first-class object, and that means that you can't assign in to a variable. The closest thing to this is assigning a pointer to the member function to a variable, but in order to call a pointer to a member function, you need to have a pointer to the original class as well:

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

Simpler solution - capture by reference

We can capture the current class by reference, and this allows you to use add_number without any qualifiers:

#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;
}
Alecto Irene Perez
  • 10,321
  • 23
  • 46