将多种类型传递给STD ::功能C



我当前正在研究一个小库,并遇到了一个错误。我基本上要做的是像这样的语法:

Client client("", true);
client.on("ready", [](User object) {
    object.test();
});
client.run();

我打电话 _eventManager->emit("ready", new User())假设client.on();方法用我传递的给定对象发射。我传递的对象可以是多种类。

我设计它的方式,以便我使用称为"对象"的基类,并且我想传递到emit的所有类都将从Object派生。但是,我在尝试执行此操作时会遇到错误:

error C2664: 'void Discord::Client::on(const std::string &,const std::function<void (Discord::Object)> &)': cannot convert argument 2 from 'main::<lambda_54cb69ba8322d42f33e22a0f4f4926a4>' to 'const std::function<void (Discord::Object)> &' 2> z:projectsvisual studio 2015discordtestsourceexample1.cpp(12): note: Reason: cannot convert from 'main::<lambda_54cb69ba8322d42f33e22a0f4f4926a4>' to 'const std::function<void (Discord::Object)>' 2> z:projectsvisual studio 2015discordtestsourceexample1.cpp(12): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

我对自己做错了什么毫无疑问。代码:

struct Event {
    std::string name;
    std::function<void(Object object)> function;
};
void Client::on(const std::string& name, const std::function<void(Object object)>& function) {
    _eventManager->add(name, function);
}
void Client::run() {
    User object;
    _eventManager->emit("ready", object);
}
void EventManager::add(const std::string& name, const std::function<void(Object object)>& function) {
    Event event;
    event.name = name;
    event.function = function;
    _events.push_back(event);
}
void EventManager::emit(const std::string& name, const Object& object) {
    for (unsigned int i = 0; i < _events.size(); i++) {
        Event& event = _events[i];
        if (event.name == name) {
            event.function(object);
        }
    }
}

错误先感谢您。

您的功能被声明为Object对象:

std::function<void(Object object)> function;

但是您通过了 User的lambda:

client.on("ready", [](User object) {
    object.test();
});

这是您要寻找的吗?

client.on("ready", [](Object object) {
    auto& user = static_cast<User&>(object);  // not safe
    user.test();
});

请注意,如果您尝试访问属于User类的任何字段,而不是Object类(这可能是一个不确定的行为(,则可能会崩溃您的应用程序,因为它是通过值" SLICES"数据传递的。您可能应该做的是通过指针/参考:

client.on("ready", [](Object& object) {   // <-- by ref here
    auto& user = static_cast<User&>(object);  // safer, at least won't crash when you pass User object
    user.test();
});

请注意,这需要一些主要的重构。不仅在各处添加&,而且您现在必须担心这些对象的寿命。

也可以尝试以下类似的东西。.我制作了参数指针以防止切片,但是问题的实际解决方案是createFunc函数,该函数将lambda中传递的lambda绑定到内部一个那称通过了兰伯达。它确保通过的类来自Object

#include <iostream>
#include <functional>
#include <vector>
class Object;
struct Event {
    std::string name;
    std::function<void(Object* object)> function;
};
class Client
{
private:
    std::vector<Event> events;
public:
    void on(const std::string& name, const std::function<void(Object* object)>& function)
    {
        this->events.push_back(Event{name, function});
    }
    void run()
    {
        for (Event &e : events)
        {
            e.function(nullptr);
        }
    }
};

class Object
{
};
class User : public Object
{
};
template<typename T>
typename std::enable_if<std::is_base_of<Object, T>::value, std::function<void(Object*)>>::type
createFunc(std::function<void(T*)> func)
{
    auto call = [](std::function<void(T*)> func, Object *ptr)
    {
        func(dynamic_cast<T *>(ptr));
    };
    return std::bind(call, func, std::placeholders::_1);
}
int main(int argc, const char * argv[]) {
    Client c;
    auto lambda = [](User* usr) {
        std::cout<<"Lambda calledn";
    };
    c.on("Hello", createFunc<User>(lambda));
    c.run();
    return 0;
}

CreateFunc基本与:

template<typename T>
void callFuncHelper(std::function<void(T*)> func, Object *ptr)
{
    func(dynamic_cast<T*>(ptr));
};

template<typename T>
typename std::enable_if<std::is_base_of<Object, T>::value, std::function<void(Object*)>>::type
createFunc(std::function<void(T*)> func)
{
    return std::bind(callFuncHelper<T>, func, std::placeholders::_1);
}

和类似:

Client c;
auto lambda = [](User* usr) {
    std::cout<<"Lambda calledn";
};
c.on("Hello", createFunc<User>(lambda));
c.run();

为什么?因为我找不到另一种推论lambda参数的方法,因此您必须将其作为模板参数传递。

最新更新