C++ 使用空参数包显式调用可变函数模板
考虑一下这个简单(不好)的函数模板,它在这个站点上有很多变体:C++ 使用空参数包显式调用可变函数模板,c++,templates,c++11,template-argument-deduction,C++,Templates,C++11,Template Argument Deduction,考虑一下这个简单(不好)的函数模板,它在这个站点上有很多变体: template <typename R, typename... Args> R call_with(std::function<R(Args...)> f, Args... args) { return f(args...); } 模板 用(std::函数f)调用, Args…Args) { 返回f(args…); } 两次尝试称之为: call_with([]{});
template <typename R, typename... Args>
R call_with(std::function<R(Args...)> f,
Args... args)
{
return f(args...);
}
模板
用(std::函数f)调用,
Args…Args)
{
返回f(args…);
}
两次尝试称之为:
call_with([]{}); // (a)
call_with<void>([]{}); // (b)
使用([]{});//(a)
用([]{});//调用_(b)
我不能调用(a)
,因为lambda不是std::函数
,所以模板推导失败。直截了当
但是,(b)
也会失败。我怀疑这是因为编译器无法确定我的意思是提供所有类型参数和原因,而我只是提供了R
——因此它试图(并且失败)推断Args…
,原因与初始调用失败的原因相同
是否有一种方法可以明确指定我正在提供所有的模板参数?为了澄清,我只对如何显式提供模板参数而不进行模板推导感兴趣,我不是在寻找用编写call_的正确方法,也不是在寻找用lambda调用时使模板推导成功的方法 对您的已编辑问题的简短回答是:如果您无法更改call\u with()
的声明,那么可以使用@CoffeeandCode演示的类型转换,或者使用下面描述的技术为call\u with()
创建包装
问题在于编译器试图从第一个函数参数推断模板参数。如果您编写的代码如下所示,则可以防止出现这种情况:
总之,如果要防止编译器推断也显示为函数参数的函数模板参数类型,请将它们包装在元函数中,例如identity
您可以事先指定函数类型,如下所示:
int main(){
std::function<void()> f = []{};
call_with(f);
}
这适用于任何函数或函子类型。这也是使用尾部返回类型的一个很好的例子
即使我提供参数,我也会看到失败:@JayMiller对,同样的想法。虽然如果我们重写call_with
始终使用单个参数(template R call_with(std::function,a);
),那么显式提供模板参数就可以了(call_with([](int){},42);
)。这只是一个顽固的参数包案例。我不应该删除我之前的评论,这让@Barry澄清了这不是一个关于如何回避这个问题的问题,所问的问题完全是书面的。“有没有办法明确指定…”虽然都是真的,但这根本不能回答问题。问题严格地说是关于显式地为call\u提供所有类型的
,而不是关于如何正确地编写该函数。@Barry我在回答的第一部分给出了一种方法来指定您对call\u的调用。使用static\u cast
只是告诉编译器为这些模板参数放置什么。不,不是这样。它正在更改参数类型,以便模板推断能够成功。我正在寻找一种完全不涉及模板推导的解决方案。如何将std::function
从std::function
更改为?在签名中显式地编写std::function
,这只是显式地转换lambda。当然可以<代码>模板void foo(T){};傅(42),
调用foo
,并且不做模板推断(这将实例化foo
),这很聪明,而且肯定让我避免了推断(+1)。虽然需要修改签名,但这是很不幸的。是的,我担心对于给定的签名,编译器总是会尝试推导模板参数——并且失败,除非第一个参数的类型是std::function。
template <typename R, typename... Args>
R call_with( typename identity<std::function<R(Args...)>>::type f,
typename identity<Args>::type... args)
int main(){
std::function<void()> f = []{};
call_with(f);
}
int main(){
call_with(static_cast<std::function<void()>>([]{}));
}
template<typename Functor, typename ... Args>
auto wrapper(Functor &&f, Args &&... args) -> decltype(f(std::forward<Args>(args)...)){
return f(std::forward<Args>(args)...);
}