Компилятор параметров шаблона c ++ не может вывести - PullRequest
0 голосов
/ 20 сентября 2019

здесь есть функция для регистрации.

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.Как я могу получить первый на работе?

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Как я могу получить первый на работе?

Я вижу несколько способов.

(1) Если вы можете изменить функцию RegisterCmdHandler() и вам не нужно знать внутри, какие типы ReqT и RestT, я предлагаю вам вообще избегать 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, лямбда-выражением (также общим лямбда, так что это решениеболее гибкий, чем использование std::function), другой тип класса / структуры с operator(), значением, возвращаемым из std::bind.Вкратце: универсальный вызываемый.

(2) Если вы можете изменить функцию RegisterCmdHandler() , но , вам нужно знать (и использовать) ReqT и RestT, выМожет следовать обычному указателю на функцию (синтаксис см. в ответе Максима Егорушкина).К сожалению, это работает только с указателями на функции и не работает (например), когда sync_handler является лямбда-выражением.

(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);

, но мне кажется, почти то же самое.

1 голос
/ 20 сентября 2019

Как получить первый на работе?

Добавить перегрузку для простых указателей функций:

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);
}
...