Проблема в том, что лямбда может быть преобразована в std::function
, но не std::function
.
Так что тип T
не может быть выведен, потому что у вас нетstd::function
и std::function
невозможно получить, потому что вы не знаете T
.
Этакая проблема с курицей и яйцом.
Так что вам нужно пройти std::function
до handleNativeCrash()
return my_namespace::handleNativeCrash(env, std::function{[&]{/*...*/}});
или вы должны получить общий вызываемый элемент, как в ответе YSC, или, например, что-то следующее (спасибо Холту за указание на мою первоначальную ошибку):
template <typename R = void, typename F,
typename T = std::conditional_t<std::is_same_v<void, R>,
decltype(std::declval<F>()()), R>>
std::optional<T> handleNativeCrash(JNIEnv *env, F f) {
try {
return std::optional<T>(f());
}
catch (const std::exception &e) {
jniThrowException(env, e.what());
return {};
}
}
Решение YSC (обнаружение возвращаемого типа с использованием decltype()
в конце типа возврата) навязывает тип, возвращаемый функционалом;использование дополнительных (со значениями по умолчанию) параметров шаблона позволяет также «перехватывать» возвращаемый тип, объясняя его.
Предположим, у вас есть l
лямбда, которая возвращает int
, но вы хотите std::optional<long>
, выможно написать что-то как
return my_namespace::handleNativeCrash<long>(env, l);