简体   繁体   中英

How do I write a lambda expression that looks like a method?

I've been going nuts trying to figure this out. Consider the following code (I'm assuming forward references have been defined):

// Signature representing a pointer to a method call
typedef
   void (MyClass::*MyMethod)(int);

class MyClass
{
    MyClass();
    void method1(int i);
    void method2(int i);

    void associateMethod(int index, MyMethod m);
} 

Given the above, the constructor can do things like the following:

MyClass::MyClass()
{
   associateMethod(1, &MyClass::method1);
   associateMethod(2, &MyClass::method2);
}

However, I'd like to be able to invoke 'associateMethod' where the second parameter is an anonymous method. However, the following doesn't compile.

associateMethod(3, [this](int) -> void { /* some code here */ }

I get an error about their being no viable conversion from the lambda to MyMethod.

I'm wondering if the lambda syntax needs to include 'MyClass' somewhere but random guesses for the lambda expression such as

 MyClass::[this](int) -> void {}

or

 [this]&MyClass::(int) -> void {}

don't compile.

Would appreciate any pointers (no pun intended)

Thanks

You can't convert a lambda expression to a class member function pointer and there's no valid syntax to make it look like one 1 .

Instead of a raw function pointer, you should declare the MyMethod as std::function signature (as was mentioned in the comments):

using MyMethod = std::function<void(int)>;

You can use lambdas then to initialize this parameter then:

MyClass::MyClass()
{
   associateMethod(1, [this](int a) { this->method1(a); });
   associateMethod(2, [this](int a) { this->method2(a); });
}

1) Lambda functions can be thought as compiler generated callable classes, which take the captures as parameters on construction and provide a operator()() overload with the parameters and body you specify. Hence there's no possible valid conversion to a raw or member function pointer.

user0042 's answer seems the way to go but, just for completeness sake, it's worth mentioning that in C++17 captureless lambdas have a constexpr conversion operator to their function pointer type, hence you should(*) be able of converting such a lambda to a member function pointer, via something like:

// ...
void associateMethod(int index, MyMethod m);

template<typename F>
void associateMethod(int index, F m) {
  associateMethod( index,
    static_cast<MyMethod>(
      &MyClass::bindFun< static_cast<void(*)(MyClass*,int)>(m) >
    ) );
}

private:

template<auto F>
void bindFun(int x){ (*F)(this,x); }

// to be used like 
x.associateMethod(0,[](MyClass* this_, int x){ this_->method1(x+1); });

(*) sadly, this compiles in clang but gcc refuses to compile it (I'm going to ask a question about this, you can find it here ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM