today I'm struggling with C++ templates. This is my simple code for convenient exception handling in JNI code.
template<typename T>
std::optional<T> handleNativeCrash(JNIEnv *env, std::function<T(void)> f) {
try {
return std::optional<T>(f());
}
catch (const std::exception &e) {
jniThrowException(env, e.what());
return {};
}
}
When I try to use it without specifying T
, Clang fails roughly with this error
no matching function for call to 'handleNativeCrash'
return my_namespace::handleNativeCrash(env, [&]{
^~~~~~~~~~~~~~~~~~~~~
/......../jni.cpp:116:39)'
std::optional<T> handleNativeCrash(JNIEnv *env, std::function<T(void)> f) {
^
1 error generated.
I would like to infer T
automatically from lambda return type. I tried to write deduction guide, but it seems that I'm unable to write it for global function. I tried to create simple template struct which contained only this function, but I failed too. It seems I don't really understand C++ template metaprogramming.
My first attempt was like this, but Clang just crashed complaining about illegal syntax and printing it's backtrace. I will report bug soon, but I need to finish this job first.
template<typename T>
handleNativeCrash(JNIEnv *env, std::function<T(void)> f) -> handleNativeCrash<decltype(f())>;
How can I achieve my goal?
You cannot use template deduction for that, it's not smart enough and only works on matching.
But you can manually infer it:
template<class Callable>
auto handleNativeCrash(JNIEnv *env, Callable f)
-> std::optional<decltype(f())>
{
try {
return f();
}
catch (const std::exception &e) {
jniThrowException(env, e.what());
return {};
}
}