![](/img/trans.png)
[英]Call a function with parameter from a pack of functors in variadic template
[英]explicit call to variadic function template with empty parameter pack
考虑这个简单(坏)函数模板,该站点上存在许多变体:
template <typename R, typename... Args>
R call_with(std::function<R(Args...)> f,
Args... args)
{
return f(args...);
}
两次尝试称它为:
call_with([]{}); // (a)
call_with<void>([]{}); // (b)
我不能调用(a)
因为lambda不是std::function<R(Args...)>
所以模板推导失败。 直截了当。
但是, (b)
也失败了。 我怀疑这是因为编译器无法确定我的意思是提供所有类型的参数和原因,我只是简单地提供R
- 因此它正在尝试(并且失败)推断出Args...
原因与初始调用失败的原因相同。
有没有办法明确指定我提供所有模板参数? 为了澄清,我只对如何显式提供模板参数感兴趣,以便没有模板推导 - 我不是在寻找写入call_with
的正确方法, call_with
是在使用lambda调用时使模板推导成功的方法。
对你编辑的问题的简短回答是:如果你不能改变call_with()
的声明,那么要么使用@CoffeeandCode演示的类型转换,要么使用下面描述的技术为call_with()
创建一个包装器。
问题在于编译器试图从第一个函数参数中推导出模板参数。 您可以防止这一点,如果你写你的代码,像这样 :
#include <functional>
#include <iostream>
// identity is a useful meta-function to have around.
// There is no std::identity, alas.
template< typename T>
struct identity
{
using type = T;
};
template <typename R, typename... Args>
R call_with( typename identity<std::function<R(Args...)>>::type f,
Args... args)
{
return f(args...);
}
int main()
{
call_with<void>([](int){ std::cout << "called" << std::endl; }, 2);
}
使用模板元函数“生成”std :: function类型意味着编译器甚至不能尝试从第一个参数推导出函数类型,它只会使用其他参数。
您仍然需要显式提供返回类型,但是对于其他参数,您现在可以选择是显式指定它们还是将其留给编译器从给定的参数中推导出它们。
如果您确实希望强制提供所有模板参数而不是推导出,那么您也可以通过以下方式将参数包包装在一个identity
调用中:
template <typename R, typename... Args>
R call_with( typename identity<std::function<R(Args...)>>::type f,
typename identity<Args>::type... args)
总之,如果要阻止编译器推导出也作为函数参数出现的函数模板参数类型,请将它们包装在元函数(如identity
。
您可以事先指定函数类型,如下所示:
int main(){
std::function<void()> f = []{};
call_with(f);
}
或者,以一种更混乱但更紧凑的方式:
int main(){
call_with(static_cast<std::function<void()>>([]{}));
}
这是因为编译器在要求它隐式地将lambda(由编译器定义的未指定函数对象)隐式转换为带有这些模板的std::function
之前,编译器不知道要为模板参数推导出什么返回类型和参数。参数。
实际上,您应该将函数warpper更改为更通用:
template<typename Functor, typename ... Args>
auto wrapper(Functor &&f, Args &&... args) -> decltype(f(std::forward<Args>(args)...)){
return f(std::forward<Args>(args)...);
}
这适用于任何函数或函子类型。 它也是使用尾随返回类型的一个很好的例子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.