模板参数和std :: function参数的推论 [英] Template argument and deduction of std::function parameters

查看:116
本文介绍了模板参数和std :: function参数的推论的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个模板函数 foo()可以接受任意数量的参数。鉴于最后一个参数始终是 std :: function ,如何实现下面所示的 foo()模板, CbArgs 包含此 std :: function 参数的方式?

Assume there is a template function foo() which accepts an arbitrary number of arguments. Given the last argument is always an std::function, how do I implement a foo() template shown below in a way that CbArgs would contain this std::function's parameters?

template<typename... InArgs, typename... CbArgs = ???>
//                                       ^^^^^^^^^^^^
void foo(InArgs... args) { ... }

例如, CbArgs 应该为 {int,int} 如果像这样调用:

For example, CbArgs should be {int,int} if invoked like this:

std::function<void(int,int)> cb;
foo(5, "hello", cb);

我的第一个想法是:

template<typename... InArgs, typename... CbArgs>
void foo(InArgs... args, std::function<void(CbArgs...)>) { ... }

但这无法编译:

note:   template argument deduction/substitution failed:
note:   mismatched types ‘std::function<void(CbArgs ...)>’ and ‘int’
  foo(5, "hello", cb);

问题一:

为什么不这个编译?为什么模板参数推导失败?

Question One:
Why doesn't this compile? Why does the template argument deduction fail?

最终,我提出了以下解决方案:

Eventually, I came up this solution:

template<typename... InArgs, typename... CbArgs>
void fooImpl(std::function<void(CbArgs...)>, InArgs... args) { ... }

template<typename... InArgs,
         typename CbType = typename std::tuple_element_t<sizeof...(InArgs)-1, std::tuple<InArgs...>>>
void foo(InArgs... args)
{
    fooImpl(CbType{}, args...);
}

此处 CbType InArgs 中的最后一个类型是 std :: function 。然后将 CbType 的临时变量传递给 fooImpl(),其中 CbArgs 被推导。这行得通,但对我来说却很难看。

Here CbType is the last type in InArgs which is std::function. Then a temporary of CbType is passed to fooImpl() where CbArgs are deduced. This works, but looks ugly to me.

问题二:

我想知道如果没有更好的解决方案有两个功能和 CbType 的临时实例?

推荐答案


为什么不编译?为什么模板参数推导失败?

Why doesn't this compile? Why does the template argument deduction fail?

parameter pack 不是最后一个参数时,无法推论。告诉编译器 InArgs ... 的内容将使您的 foo 定义起作用:

When a parameter pack is not the last parameter, it cannot be deduced. Telling the compiler the contents of InArgs... will make your foo definition work:

template<typename... InArgs, typename... CbArgs>
void foo(InArgs..., std::function<void(CbArgs...)>) { }

int main()
{
    std::function<void(int,int)> cb;
    foo<int, const char*>(5, "hello", cb);
}

或者,正如您在解决方法中发现的那样,只需将 InArgs ... 最后更新您的 foo 调用:

Alternatively, as you discovered in your workaround, simply put InArgs... at the end and update your foo invocation:

template<typename... InArgs, typename... CbArgs>
void foo(std::function<void(CbArgs...)>, InArgs...) { }

int main()
{
    std::function<void(int,int)> cb;
    foo(cb, 5, "hello");
}








我想知道是否有没有两个功能以及 CbType 的临时实例的更好的解决方案?

I wonder if there is a better solution without having two functions and a temporary instance of CbType?

这是避免不必要的临时实例的一种可能方法,但使用相同的机制来扣除 CbArgs ... :只需包装 CbType 在一个空包装中,然后将其传递给 fooImpl

Here's a possible way of avoiding the unnecessary temporary instance but using your same mechanism for the deduction of CbArgs...: simply wrap CbType in an empty wrapper, and pass that to fooImpl instead.

template <typename T>
struct type_wrapper
{
    using type = T;
};

template<typename... InArgs, typename... CbArgs>
void fooImpl(type_wrapper<std::function<void(CbArgs...)>>, InArgs&&...) { }

template<typename... InArgs,
         typename CbType = 
             std::tuple_element_t<sizeof...(InArgs)-1, 
                 std::tuple<std::remove_reference_t<InArgs>...>>>
void foo(InArgs&&... args)
{
    fooImpl(type_wrapper<CbType>{}, std::forward<InArgs>(args)...);
}

其他改进:


  • typename CbType = 之后的 typename 是不必要的-已将其删除

  • The typename after typename CbType = was unnecessary - it was removed.

args ... 应该完美地转发到 fooImpl 保留其值类别 foo fooImpl 都应使用 args ... 作为转发参考

args... should be perfectly-forwarded to fooImpl to retain its value category. Both foo and fooImpl should take args... as a forwarding-reference.

wandbox示例

请注意,有一项建议可以使处理非终端参数包的方式更容易: P0478R0-非终端
函数参数包的模板参数推导
。这样可以使您的原始实现按预期工作。

Note that there is a proposal that would make dealing with non-terminal parameter packs way easier: P0478R0 - "Template argument deduction for non-terminal function parameter packs". That would make your original implementation work as intended.

这篇关于模板参数和std :: function参数的推论的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆