c ++模板参数编译器无法推断
c++ template parameter compiler can not deduce
这里是注册函数
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
以及要注册的特定处理程序:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
现在我想将处理程序应用于注册函数,编译器抱怨
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
而具体写出来类型就可以了:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
但后者有丑API。我怎样才能得到第一个工作?
How can I get the first on work?
为普通函数指针添加重载:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
我看到了一些方法。
(1)如果可以修改RegisterCmdHandler()
函数and就不需要知道,里面的ReqT
和[是什么类型=18=] 是,我建议你完全避免 std::function
并接受 sync_handler
作为简单的模板类型。
我是说
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
这是一个非常灵活的解决方案,因为F
可以是一个函数,一个函数指针,一个std::function
,一个lambda(也是一个通用的lambda,所以这个解决方案比使用std::function
),另一种类型的 class/struct 带有 operator()
,一个从 std::bind
返回的值。简而言之:一个通用的可调用对象。
(2) 如果你可以修改 RegisterCmdHandler()
函数 但是 你需要知道(并使用) ReqT
和 RestT
,您可以遵循简单的函数指针方式(有关语法,请参阅 Maxim Egorushkin 的回答)。不幸的是,这仅适用于函数指针,并且在 sync_handler
是 lambda 时不起作用(通过示例)。
(3)如果不能修改RegisterCmdHandler()
但可以使用C++17,可以使用std::function
推导指南,调用函数如下
RegisterCmdHandler(1, std::function{SomeHandler});
或者,如果你必须在不同的地方调用它,通过转换器调用它可能更好
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
调用如下
CallRegisterCH(1, SomeHandler);
(4) 如果你不能修改 RegisterCmdHandler()
并且你必须使用 C++11 或 C++14...那么...解释模板类型
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
在我看来更好的方法。
您可以通过其他方式显式 std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
但在我看来几乎是一回事。
这里是注册函数
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
以及要注册的特定处理程序:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
现在我想将处理程序应用于注册函数,编译器抱怨
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
而具体写出来类型就可以了:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
但后者有丑API。我怎样才能得到第一个工作?
How can I get the first on work?
为普通函数指针添加重载:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
我看到了一些方法。
(1)如果可以修改RegisterCmdHandler()
函数and就不需要知道,里面的ReqT
和[是什么类型=18=] 是,我建议你完全避免 std::function
并接受 sync_handler
作为简单的模板类型。
我是说
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
这是一个非常灵活的解决方案,因为F
可以是一个函数,一个函数指针,一个std::function
,一个lambda(也是一个通用的lambda,所以这个解决方案比使用std::function
),另一种类型的 class/struct 带有 operator()
,一个从 std::bind
返回的值。简而言之:一个通用的可调用对象。
(2) 如果你可以修改 RegisterCmdHandler()
函数 但是 你需要知道(并使用) ReqT
和 RestT
,您可以遵循简单的函数指针方式(有关语法,请参阅 Maxim Egorushkin 的回答)。不幸的是,这仅适用于函数指针,并且在 sync_handler
是 lambda 时不起作用(通过示例)。
(3)如果不能修改RegisterCmdHandler()
但可以使用C++17,可以使用std::function
推导指南,调用函数如下
RegisterCmdHandler(1, std::function{SomeHandler});
或者,如果你必须在不同的地方调用它,通过转换器调用它可能更好
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
调用如下
CallRegisterCH(1, SomeHandler);
(4) 如果你不能修改 RegisterCmdHandler()
并且你必须使用 C++11 或 C++14...那么...解释模板类型
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
在我看来更好的方法。
您可以通过其他方式显式 std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
但在我看来几乎是一回事。