简体   繁体   中英

C++ Lambda to Function Pointer

I have three classes:

class ShapeEditor {}
class PointEditor: ShapeEditor{}
class RectEditor: ShapeEditor{}

I want to define a function pointer in Manager class and pass it in constructor as lambda function. It looks like this:

class Manager {
public:
  ShapeEditor (*factory)();
  Manager(ShapeEditor (*_factory)());
}

Then I'm writing in main:

Manager m = Manager([] { return PointEditor(); }

and getting an error message that there is no constructor for this expression.

When I changes ShapeEditor to PointEditor in Manager - it works fine, but I need to specify different types in function result.

@NathanOliver gave the correct answer in comments above:

Yes, but you didn't specify a return type for the lambda, so it gets it from the returned object, and that object doesn't have the same type as the return type your function pointer needs

So here is my solution:

Manager m = Manager([] -> ShapeEditor* { return new PointEditor(); });

Your problem is that your lambda returns object value of type ShapeEditor which inherits from ShapeEditor and base class value is expected.

Basically you are expecting some kind of polymorphism, but you return value of some specific child type when you expect value for base type! This leads to silent conversion and as a result behavior is different then you expect so your answer is incorrect.

If you need polymorphism you need use a pointer or reference:

#include <memory>
#include <string>

class ShapeEditor {
public:
    virtual ~ShapeEditor() {}
    virtual std::string doSomething() = 0;
};

class PointEditor: public ShapeEditor {
public:
    std::string doSomething() override;
};

class RectEditor: public ShapeEditor{
public:
    std::string doSomething() override;
};

using ShapeEditorPtr = std::unique_ptr<ShapeEditor>;

class Manager {
public:
  ShapeEditorPtr (*factory)();

  Manager(ShapeEditorPtr (*_factory)());
};

void test() {
    Manager m = Manager([]() -> ShapeEditorPtr { 
        return std::make_unique<PointEditor>();
    });
}

https://godbolt.org/z/xP4czj

as I can see that your problem is to try casting a PointEditor instance into a ShapeEditor instance. You need to cast Pointers, instead of values. So, in your lambda expression, you are returning a COPY of local instance PointEditor and trying to copy it into a ShapeEditor local variable.

Here is my proposal:

#include <cmath>
#include <cstdio>
#include <map>
#include <iostream>

using namespace std;

class ShapeEditor {
public:
    virtual void printName(){};
};

class PointEditor: ShapeEditor{
    
public:
    void printName(){cout << "PointEditor\n";};
};

class RectEditor: ShapeEditor{
    
public:
    void printName(){cout << "RectEditor\n";};
};

class Manager {
    ShapeEditor* shp;
    ShapeEditor* (*factory) ();
public:
    Manager( ShapeEditor* (*_factory)() ):factory{_factory}{
        shp = factory();
        shp->printName();
    };
    
    ~Manager(){delete shp;}
};

int main()
{
    
    ShapeEditor* (*func1)() = [](){
        PointEditor* x = new PointEditor();
        ShapeEditor* s = (ShapeEditor*)x;
        return s;
        
    };
    
    ShapeEditor* (*func2)() = [](){
        RectEditor* x = new RectEditor();
        ShapeEditor* s = (ShapeEditor*)x;
        return s;
    };
    
    Manager m1 = Manager(func1);
    Manager m2 = Manager(func2);
    
    return 0;
}

the output:

PointEditor
RectEditor

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