用于将任何lambda函数(包括捕获lambda)转换为std :: function对象的模板

1992年

我有以下代码可以将lambda转换为C样式的函数指针。这适用于所有lambda,包括具有捕获功能的lambda。

#include <iostream>
#include <type_traits>
#include <utility>

template <typename Lambda>
struct lambda_traits : lambda_traits<decltype(&Lambda::operator())>
{};

template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<Return(Lambda::*)(Args...)> : lambda_traits<Return(Lambda::*)(Args...) const>
{};

template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<Return(Lambda::*)(Args...) const>
{
    using pointer = typename std::add_pointer<Return(Args...)>::type;

    static pointer to_pointer(Lambda&& lambda)
    {
        static Lambda static_lambda = std::forward<Lambda>(lambda);
        return [](Args... args){
            return static_lambda(std::forward<Args>(args)...);
        };
    }
};

template <typename Lambda>
inline typename lambda_traits<Lambda>::pointer to_pointer(Lambda&& lambda)
{
    return lambda_traits<Lambda>::to_pointer(std::forward<Lambda>(lambda));
}

可以使用以下方法将带有捕获的lambda传递到C风格的API中:


// Function that takes a C-style function pointer as an argument
void call_function(void(*function)())
{
    (*function)();
}

int main()
{
    int x = 42;

    // Pass the lambda to the C-style API
    // This works even though the lambda captures 'x'!
    call_function(to_pointer([x] {
        std::cout << x << std::endl;
        }));
}

鉴于此,编写一个类似的模板可以将lambda(包括带有捕获的lambda)一般地转换为std::function对象似乎相对简单,但是我在努力寻找方法。(我对模板元编程技术不是很熟悉,所以我有点迷路了)

这是我尝试过的,但是无法编译:

template <typename Lambda>
struct lambda_traits : lambda_traits<decltype(&Lambda::operator())>
{};

template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<typename std::function<Return(Args...)>> : lambda_traits<typename std::function<Return(Args...)> const>
{};

template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<typename std::function<Return(Args...)> const>
{
    using pointer = typename std::function<Return(Args...)>*;

    static pointer to_pointer(Lambda&& lambda)
    {
        static Lambda static_lambda = std::forward<Lambda>(lambda);
        return [](Args... args) {
            return static_lambda(std::forward<Args>(args)...);
        };
    }
};

template <typename Lambda>
inline typename lambda_traits<Lambda>::pointer to_pointer(Lambda&& lambda)
{
    return lambda_traits<Lambda>::to_pointer(std::forward<Lambda>(lambda));
}

这无法编译,并表示Lambda部分专门化未使用template参数。

正确的方法是什么?

(请注意,我一直使用兼容C ++ 11的编译器,因此C ++ 14及更高版本的功能不可用)

贾斯汀

如果要在std::function不指定的签名的情况下将可调用对象转换为std::function,则这正是C ++ 17的推论指南std::function所针对的。我们只需要为C ++ 11实现一个版本即可。注意,这仅适用于非重载的可调用对象operator()否则,将无法执行此操作。

#include <functional>
#include <utility> // std::declval

// Using these functions just for the return types, so they don't need an implementation.

// Support function pointers
template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;

// Support callables (note the _impl on the name).
// Many overloads of this to support different const qualifiers and
// ref qualifiers. Technically should also support volatile, but that
// doubles the number of overloads and isn't needed for this illustration.
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const) -> std::function<R(ArgTypes...)>;

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &) -> std::function<R(ArgTypes...)>;

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&) -> std::function<R(ArgTypes...)>;

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &&) -> std::function<R(ArgTypes...)>;

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&&) -> std::function<R(ArgTypes...)>;

// To deduce the function type for a callable, get its operator() and pass that to
// the _impl functions above.
template <typename Function>
auto deduce_std_function(Function)
    -> decltype(deduce_std_function_impl(&Function::operator()));

template <typename Function>
using deduce_std_function_t = decltype(deduce_std_function(std::declval<Function>()));

template <typename F>
auto to_std_function(F&& fn) -> deduce_std_function_t<F> {
    return deduce_std_function_t<F>(std::forward<F>(fn));
}

演示版


更详细的解释

我们需要推导的函数类型std::function<...>因此,我们需要实现某种deduce_std_function确定功能类型的方法。有几种方法可以实现此目的:

  • function_traits输入一个可以为我们确定功能类型的类型(类似于您的lambda_traits)。
  • 实现deduce_std_function为重载集,其中重载的返回类型是推导类型。

我之所以选择后者,是因为它模仿了演绎指南。前者也可以,但是我认为这种方法可能更简单(函数样板比结构样板小)。

简单的情况

查看有关std::function演绎指南的文档,有一个简单的方法:

template<class R, class... ArgTypes>
function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;

这很容易翻译:

template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;

基本上,给定任何函数指针R(*)(ArgTypes...),我们想要的类型是std::function<R(ArgTypes...)>

棘手的情况

文档指出第二种情况是:

对于某些类类型G,如果&F::operator()重载视为未经评估的操作数时decltype(&F::operator())格式正确形式为R(G::*)(A...)(可选cv限定,可选noexcept,可选为左值引用限定),则此重载仅参与重载解析std::function<R(A...)>

满嘴 但是,这里的关键思想是:

  • decltype(&F::operator())具有以下形式R(G::*)(A...)
  • “推导的类型是std::function<R(A...)>

这意味着我们需要获取指向成员函数的指针,operator()并将该指向成员函数的签名用作的签名std::function

那是从哪里来的:

template <typename Function>
auto deduce_std_function(Function)
    -> decltype(deduce_std_function_impl(&Function::operator()));

我们之所以委托,deduce_std_function_impl是因为我们需要推断出指向member-member-function的签名&Function::operator()

该impl函数有趣的重载为:

template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;

简而言之,我们获取了R ... (ArgTypes...)指向成员函数指针的签名(位)并将其用于std::function语法的其余部分(该(F::*)位)仅是指向成员函数指针的语法。R(F::*)(ArgTypes...)F具有签名R(ArgTypes...)且没有const,volatile或reference限定符的类的指向成员函数的指针的类型

可是等等!我们要支持const和reference限定符(您可能还希望增加对volatile的支持)。因此,我们需要deduce_std_function_impl对每个限定符重复以上内容:

签名 类声明
R(F::*)(ArgTypes...) void operator()();
R(F::*)(ArgTypes...) const void operator()() const;
R(F::*)(ArgTypes...) & void operator()() &;
R(F::*)(ArgTypes...) const& void operator()() const&;
R(F::*)(ArgTypes...) && void operator()() &&;
R(F::*)(ArgTypes...) const&& void operator()() const&&;

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

用于将任何lambda函数(包括捕获lambda)转换为std :: function对象的模板

来自分类Dev

用于将任何lambda函数(包括捕获lambda)转换为std :: function对象的模板

来自分类Dev

将对象(包括lambda)转换为JSON,反之亦然

来自分类Dev

C ++ ::模板函数-从object.function获取对象的地址

来自分类Dev

C ++ 11 Lambda函数隐式转换为bool vs.std :: function

来自分类Dev

C ++ 11 Lambda函数隐式转换为bool vs.std :: function

来自分类Dev

函数模板,用于将字符串文字转换为std :: array

来自分类Dev

这些将安全数组转换为std :: list对象的方法是否可以转换为模板函数?

来自分类Dev

为什么C ++ 11不将lambda隐式转换为std :: function对象?

来自分类Dev

将函数指针实现替换为std :: function,以便在PlayFab SDK中使用lambda

来自分类Dev

将lambda应用于模板参数包;未捕获lambda参数

来自分类Dev

将模板 lambda 转换为 `void *` 是否安全?

来自分类Dev

std :: function模板函数

来自分类Dev

将“ AWS :: Lambda :: Function”转换为“ AWS :: Serverless :: Function”

来自分类Dev

如何将Lambda参数转换为可用对象?

来自分类Dev

如何将lambda表达式转换为对象?

来自分类Dev

如何将浏览器返回的json对象转换为python lambda函数中的字符串

来自分类Dev

Java 8:将POJO转换为映射列表-ID-POJO = Stream中的映射(Function <?super C,?>)无法应用于(<lambda expression>,<lambda expression>)

来自分类Dev

std :: async,std :: function对象和带有'callable'参数的模板

来自分类Dev

std :: async,std :: function对象和带有'callable'参数的模板

来自分类Dev

将输入参数传递给lambda函数中的std :: function

来自分类Dev

传递模板函数进行无lambda转换

来自分类Dev

如何将列表转换为用于烧瓶模板的类对象

来自分类Dev

如何在推断的上下文中将std :: bind(或lambda)转换为std :: function?

来自分类Dev

std :: function模板语法

来自分类Dev

std :: function模板语法

来自分类Dev

编写为用于功能对象的类是否也可以用于lambda或std :: function类型?

来自分类Dev

C ++模板将功能转换为功能对象类型

来自分类Dev

从C ++中的std :: function访问模板化的lambda

Related 相关文章

  1. 1

    用于将任何lambda函数(包括捕获lambda)转换为std :: function对象的模板

  2. 2

    用于将任何lambda函数(包括捕获lambda)转换为std :: function对象的模板

  3. 3

    将对象(包括lambda)转换为JSON,反之亦然

  4. 4

    C ++ ::模板函数-从object.function获取对象的地址

  5. 5

    C ++ 11 Lambda函数隐式转换为bool vs.std :: function

  6. 6

    C ++ 11 Lambda函数隐式转换为bool vs.std :: function

  7. 7

    函数模板,用于将字符串文字转换为std :: array

  8. 8

    这些将安全数组转换为std :: list对象的方法是否可以转换为模板函数?

  9. 9

    为什么C ++ 11不将lambda隐式转换为std :: function对象?

  10. 10

    将函数指针实现替换为std :: function,以便在PlayFab SDK中使用lambda

  11. 11

    将lambda应用于模板参数包;未捕获lambda参数

  12. 12

    将模板 lambda 转换为 `void *` 是否安全?

  13. 13

    std :: function模板函数

  14. 14

    将“ AWS :: Lambda :: Function”转换为“ AWS :: Serverless :: Function”

  15. 15

    如何将Lambda参数转换为可用对象?

  16. 16

    如何将lambda表达式转换为对象?

  17. 17

    如何将浏览器返回的json对象转换为python lambda函数中的字符串

  18. 18

    Java 8:将POJO转换为映射列表-ID-POJO = Stream中的映射(Function <?super C,?>)无法应用于(<lambda expression>,<lambda expression>)

  19. 19

    std :: async,std :: function对象和带有'callable'参数的模板

  20. 20

    std :: async,std :: function对象和带有'callable'参数的模板

  21. 21

    将输入参数传递给lambda函数中的std :: function

  22. 22

    传递模板函数进行无lambda转换

  23. 23

    如何将列表转换为用于烧瓶模板的类对象

  24. 24

    如何在推断的上下文中将std :: bind(或lambda)转换为std :: function?

  25. 25

    std :: function模板语法

  26. 26

    std :: function模板语法

  27. 27

    编写为用于功能对象的类是否也可以用于lambda或std :: function类型?

  28. 28

    C ++模板将功能转换为功能对象类型

  29. 29

    从C ++中的std :: function访问模板化的lambda

热门标签

归档