今天,我在努力使用C ++模板。这是我在JNI代码方便异常处理简单的代码。
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 {};
}
}
当我尝试使用它,而无需指定T
,锵大致与此错误
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.
我想推断T
自动从拉姆达返回类型。我试图编写推导指南,但似乎无法为全局函数编写它。我试图创建仅包含此功能的简单模板结构,但我也失败了。看来我真的不明白C ++模板元编程。
我的第一次尝试是这样的,但是Clang崩溃了,抱怨语法不合法并打印了回溯。我很快就会在报告错误,但我需要先完成这项工作。
template<typename T>
handleNativeCrash(JNIEnv *env, std::function<T(void)> f) -> handleNativeCrash<decltype(f())>;
我如何实现我的目标?
答案 0 :(得分:8)
您不能为此使用模板推论,因为它不够聪明,只能用于匹配。
但是您可以手动推断它:
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 {};
}
}
答案 1 :(得分:0)
问题在于,lambda可以转换为std::function
,但不能转换为std::function
。
因此无法推论T
类型是因为您没有std::function
,而无法获得std::function
是因为您不知道{{1} }。
一种鸡肉和鸡蛋的问题。
因此,您必须将T
传递给std::function
handleNativeCrash()
或者您必须像YSC回答中那样收到通用可调用项,或者例如,如下所示(感谢Holt指出了我的原始错误):
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 {};
}
}
在后返回类型)施加由功能返回的类型;使用additionals(用默认值)模板参数还允许“劫持”返回类型显性化它。
假设您有一个返回decltype()
的{{1}} lambda,但想要一个l
,则可以写为
int