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() 函数 但是 你需要知道(并使用) ReqTRestT ,您可以遵循简单的函数指针方式(有关语法,请参阅 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);

但在我看来几乎是一回事。