将多种类型传递给STD ::功能C
Passing multiple types to std::function 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参数的方法,因此您必须将其作为模板参数传递。
- std ::功能作为默认参数的功能
- 复制std ::功能多么昂贵
- 将多种类型传递给STD ::功能C
- STD ::功能,字面类型和模板
- 使用STD ::功能时,编译器无法推断类型
- 调用STD ::功能,并带有变体类型列表
- STD ::功能的类型扣除额
- STD功能替换向量中的字节范围
- 如何管理STD ::功能的STD ::向量
- 绑定std ::功能错误
- 将成员函数和lambdas传递给std ::功能
- std ::功能和错误:无需匹配函数
- 如何通过C通过C API传递std ::功能
- 将std ::函数铸造到其他std ::功能并调用它
- 如何将std ::功能包装器转换为变异功能
- rvalue参考绑定到std ::功能类型的LVALUE
- lambdas不使用功能接受std ::功能
- 虚拟方法与std ::功能成员变量在性能方面
- sTD ::功能的替代方案,用于收集可可的功能
- 为什么不能将std :: stol转换为std ::功能对象