用户定义的lambda扣除指南

时间:2019-02-01 12:39:26

标签: c++ c++17 template-deduction

今天,我在努力使用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())>;

我如何实现我的目标?

2 个答案:

答案 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 {};
    }
}

Simplified live demo

答案 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