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

徘徊边缘 提交于 2020-01-04 14:19:07

问题


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


回答1:


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).




回答2:


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

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.



来源:https://stackoverflow.com/questions/47604606/how-do-i-write-a-lambda-expression-that-looks-like-a-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!