从类模板生成 lambda

Posted

技术标签:

【中文标题】从类模板生成 lambda【英文标题】:Generating lambda from class template 【发布时间】:2017-09-19 20:01:37 【问题描述】:

我有一个注册回调函数并稍后调用它们的类,如下所示。

template<typename ReturnType, typename... Args>
class Signal 
    std::vector<std::function<ReturnType(Args...)>> function;
public:
    template<typename... Args2>
    ReturnType operator()(Args2&&... args2) 
        ReturnType ret;
        for (auto& func : function)
            ret = func(std::forward<Args2>(args2)...);
        return ret;
    

    template<typename Func>
    void func(Func const &func) 
        function.push_back(std::function<ReturnType(Args...)>(func));
    

    template<typename Class, typename Instance>
    void mfunc(ReturnType(Class::*func)(Args...), Instance &instance) 
        mfunc2(func, instance, make_int_sequence<sizeof...(Args)>);
    
    template<typename Class, typename Instance, int... I>
    void mfunc2(ReturnType(Class::*func)(Args...), Instance &instance, int_sequence<I...>) 
        using namespace std::placeholders;
        function.push_back(std::function<ReturnType(Args...)>(std::bind(func, &instance, placeholder_template<I>...)));
    
;

#include <iostream>

class foo 
public:
    int bar(int x, double y) 
        std::cout << x << " and " << y << std::endl;
        return x*2;
    
;

int main() 
    foo foo1;
    Signal<int, int, double> sig;
    sig.mfunc(&foo::bar, foo1);
    std::cout << "Return: " << sig(5,5.5) << std::endl;

我今天听到了 Stephan T. Lavavej 的演讲,他说的其中一件事是应该避免 std::bind 并改用 lambdas。所以要学习一些新东西,我想我会尝试将 mfunc2 中的 std::bind 调用更改为 lambda,但我对模板很陌生,不知道如何生成我想要的代码。

我在 SO 上找到的带有 make_int_sequence 的当前 placeholder_template,但我无法真正理解它是如何工作的,或者在哪里可以找到任何好的阅读材料...

Args... 包含 lambda 应该接受的参数类型,但我需要根据 sizeof...(Args) 以某种方式创建变量名称,例如 var1、var2、var3 等,然后将它们合并在一起.

所以例如 , Args... 将持有 int, int。 然后我想将 lambda 构造为

[func, &instance](int var1, int var2) -> ReturnType  return func(&instance, var1, var2); 

我怎样才能做到这一点?

【问题讨论】:

请以minimal reproducible example开头。通过编译的东西,我们可以向您展示如何将其更改为使用可变参数 lambda。 我编辑了我的帖子以删除模板说明符,所以只要你给它一个返回类型(不是 void)和至少 1 个参数,它现在应该可以编译。 【参考方案1】:

这应该可以完成工作:

template<typename ReturnType, typename... Args>
class Signal 
    std::vector<std::function<ReturnType(Args...)>> function;
public:
    template<typename... Args2>
    ReturnType operator()(Args2&&... args2) 
        ReturnType ret;
        for (auto& func : function)
            ret = func(std::forward<Args2>(args2)...);
        return ret;
    

    template<typename Func>
    void func(Func const &func) 
        function.push_back(std::function<ReturnType(Args...)>(func));
    

    template<typename Class, typename Instance>
    void mfunc(ReturnType(Class::*func)(Args...), Instance& instance) 
        function.push_back([&instance, func](Args&&... args)  
            return (instance.*func)(std::forward<Args>(args)...); 
        );
    

;

https://ideone.com/gjPdWN

请注意,在您的 operator() 中,您基本上会丢弃除最后一个之外的所有返回值。这种行为是故意的吗?

【讨论】:

太棒了!正是我想要的。是的,除了一个返回值之外的所有返回值都是有意的,因为这是我目前所需要的。我想这些值可以放在 std::vector 中并返回,但如果我需要的话,我会在以后做一些事情。

以上是关于从类模板生成 lambda的主要内容,如果未能解决你的问题,请参考以下文章

从类内部获取模板[重复]

从类模板中排除类型

C++:当包含从类模板派生的类的标头时,编译器警告 C4505

在 Cloudformation 模板中,我如何在 IoT Rule 中引用动态生成的 Lambda 函数 ARN?

类模板中的static关键字

如何在模板类中使用 lambda 作为 STL Compare 方法?