【问题标题】:Variadic template deduction/matching for a closure class闭包类的可变参数模板推导/匹配
【发布时间】:2015-12-06 10:39:03
【问题描述】:

我正在尝试创建某种闭包回调类,但在模板参数推导和匹配方面遇到了一些问题

(该类的工作方式如下:在构造时,它会将成员或非成员函数以及变量 (CAPARGS) 数量的参数放入闭包中。然后可以使用变量号调用闭包参数(CALLARGS),它会用CAPARGSCALLARGS调用它的回调函数。)

  • 在调用其构造函数时出现编译错误(见下文 “测试代码”,标记了两个错误)。
  • 在这两种情况下都会出现编译错误,因为它找不到匹配的构造函数。
  • 我在“类代码”下标记了每个错误都应该采用的构造函数,并在下面给出了该构造函数的错误(不匹配的原因)。

错误1:

候选模板被忽略:无法将“function”与“void (*)(int)”匹配

错误2:

注意:候选模板被忽略:模板参数推导失败

类代码:

template <class... CALLARGS>
class Closure{

    public:

        // Constructor intended for use at ERROR 1
        template <class OBJ, class... CAPARGS>
        Closure(OBJ* obj, void (OBJ::*fct)(CAPARGS..., CALLARGS...), CAPARGS... capArgs){
            callback =
                [=] (CALLARGS... callArgs) -> void{
                    (obj->*fct)(capArgs..., callArgs...);
                };
        }

        // Constructor intended for use at ERROR 1
        template <class... CAPARGS>
        Closure(std::function<void(CAPARGS..., CALLARGS...)>, CAPARGS... capArgs){
            callback =
                [=] (CALLARGS... callArgs) -> void{
                    fct(capArgs..., callArgs...);
                };
        }

        void operator () (CALLARGS... callArgs){
            callback(callArgs...);
        }

    private:
        std::function<void(CALLARGS...)> callback;

};

测试代码:

class A{
    public:
        virtual void fct(int a){
            ...
        }
};


void plusF(int a){
    ...
}

int main(void) {

    A a;

    Closure<int> callF(plusF); // **ERROR 1 from here**
    Closure<int> callA(&a, &A::fct); // **ERROR 2 from here**

    callF(1);
    callA(2);

}

我知道我做的事情可能超出了我的技能范围。但是我能以某种方式解决这个问题吗?

(顺便说一句,附带问题:将此类称为 Closure 是否合理,或者这样的构造是否具有不同的名称?)

【问题讨论】:

  • 请注意std::bind 可能会有所帮助。
  • 例如,您可以将参数存储在 std::tuple 中,然后如果您有现代编译器,则可以使用 std::apply 调用该函数......它与您的解决方案有点不同
  • CAPARGS 不能从不是std::function 的任何东西中推导出来
  • @PiotrSkotnicki:不,就像在代码中一样。该函数需要能够接受CAPARGS 以及CALLARGS

标签: c++ templates c++11 variadic-templates template-argument-deduction


【解决方案1】:

您的某些可变参数模板不可扣除(或产生冲突),您可以改为:

template <class... CALLARGS>
class Closure{
public:

    template <class OBJ, typename M, class... CAPARGS>
    Closure(OBJ* obj, M (OBJ::*fct), CAPARGS... capArgs){
        callback =
            [=] (CALLARGS... callArgs) -> void{
                (obj->*fct)(capArgs..., callArgs...);
            };
    }

    template <typename F, class... CAPARGS>
    Closure(F fct, CAPARGS... capArgs){
        callback =
            [=] (CALLARGS... callArgs) -> void{
                fct(capArgs..., callArgs...);
            };
    }
    void operator () (CALLARGS... callArgs){
        callback(callArgs...);
    }
private:
    std::function<void(CALLARGS...)> callback;
};

Demo

std::bind 可能是一个更简单的选择:

using namespace std::placeholders;
A a;

auto callF = std::bind(plusF, _1);
auto callA = std::bind(&A::fct, &a, _1);

callF(1);
callA(2);

Demo

【讨论】:

  • 谢谢,有帮助。但这对我来说是一种魔力……您能推荐一个好的起点(链接、搜索词、书籍)来了解更多相关信息吗?
  • PMF 应该被简化为一个指向成员的简单指针(F O::*);因为它不处理const 成员函数等。此外,PMF 的类类型应允许与OBJ 不同,否则它将与继承的成员中断。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 2017-10-31
相关资源
最近更新 更多