模板参数和std :: function参数的推论 [英] Template argument and deduction of std::function parameters
问题描述
假设有一个模板函数 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
aftertypename 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.
请注意,有一项建议可以使处理非终端参数包的方式更容易: 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屋!