C++ 推导lambda返回和传递给构造函数的参数

C++ 推导lambda返回和传递给构造函数的参数,c++,c++17,template-argument-deduction,C++,C++17,Template Argument Deduction,我有以下课程: template<typename R, typename... Args> class Callable final { public: Callable(void* args, R(*fn)(Args...)); Callable(void* args, std::function<R(Args...)> &&fn); /* parse args into a tuple<Args...>

我有以下课程:

template<typename R, typename... Args>
class Callable final
{
public:
    Callable(void* args, R(*fn)(Args...));
    Callable(void* args, std::function<R(Args...)> &&fn);
    
    /* parse args into a tuple<Args...> and invoke callable */
    void* invoke();
    
private:
    void* args;
    std::function<R(Args...)> callable;
};
但它不允许我这样做:

Callable(args, [](void* a, void* b, void* c){}).invoke();
//No viable constructor or deduction guide for deduction of template arguments of 'Callable'
我必须将
lambda
包装在
std::函数中。是否有一种方法允许我的类直接接受lambda并将其存储为
std::function
,而不必显式地将
std::function(lambda)
指定为构造函数参数

我不想做
Callable(args,std::function([](void*a,void*b,void*c){})).invoke()
将lambda显式包装到函数中。我想直接传递lambda,让构造函数在内部将其作为函数存储


我该怎么做呢?

如果允许我们修改
Callable
的模板签名以删除包
Args…
而使用单个参数,我们可以为
Callable
编写自己的扣减指南:

template<typename Fn>
class Callable final {
public:
    Callable(void* args, std::function<Fn>&&);

    void* invoke();
    
private:
    void* args;
    std::function<Fn> callable;
};

template<typename>
struct Get_fn_type;

template<typename R, typename C, typename... Args>
struct Get_fn_type<R(C::*)(Args...) const> {
    using type = R(Args...);
};

template<typename R, typename C, typename... Args>
struct Get_fn_type<R(C::*)(Args...)> {   // for mutable lambdas
    using type = R(Args...);
};

template<class Fn>
Callable(void*, Fn) -> Callable<
    typename Get_fn_type<decltype(&Fn::operator())>::type>;

template<class Fn>
Callable(void*, Fn*) -> Callable<Fn>;


使用一个模板参数而不是pack的一个缺点可能是难以明确定义
Args…
的元组。助手类型特征可用于从
Fn
获取
std::tuple
类型:

template<typename>
struct Tuple_from_args;

template<typename R, typename... Args>
struct Tuple_from_args<R(Args...)> {
    using type = std::tuple<Args...>;
};
模板
来自参数的结构元组;
模板
来自参数的结构元组{
使用type=std::tuple;
};

@Evg,但如果我只执行
std::function(lambda)
而不指定它推断出的类型,它就会工作。。所以我想知道是否有可能去掉
std::function
部分。链接的问题指出,如果不指定类型,则无法创建
std::function
。。但是我可以这样做:S
template Callable(void*args,Fn-Fn):args(args),Callable(Fn){}
,这样编写的类就可以被
std::function
替换,并通过调用
std::bind
或lambda来初始化。@Brandon,多亏了@sandwood
std::function
可以包装捕获的lambdas,你能解释一下
C::*
符号吗?这是指向类型
C
的指针吗?您需要范围解析做什么?@User12547645,
C::*
属于
C
类。Lambda只是一种语法糖。在内部,它是一个具有成员函数
operator()
的类(具有一些唯一的名称)。因此,
C
将被推导为我们不感兴趣的唯一类型。因此,由于lambda只有一个成员函数,编译器将知道
C::*
引用了该函数?明白了:)@User12547645不完全正确。我们显式地传递指向函数的指针:
&Fn::operator()
。重要的是,我们只有一个
操作符()
,因此选择特定函数时不需要重载解析。我将模板类更改为
可调用的
,上面的代码也成功了。这样我就可以保留
Args…
来构造元组。但我还是要试试你的元组助手,看看:D
Callable(args, test).invoke();
Callable(args, std::function([](void* a, void* b, void* c){})).invoke();
Callable(args, [](void* a, void* b, void* c) {}).invoke();
Callable(args, [](void* a, void* b, void* c) mutable {}).invoke();
template<typename>
struct Tuple_from_args;

template<typename R, typename... Args>
struct Tuple_from_args<R(Args...)> {
    using type = std::tuple<Args...>;
};