如果模板没有可变参数,则将Lambda推导为std :: function [英] Lambda is deduced to std::function if template has no variadic arguments
问题描述
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
template<typename ReturnT, typename ParamT>
void bar(std::function<ReturnT(ParamT)> callback)
{}
main()
{
foo<int, int>([](int x){ return x; }); // no instance of function
// template matches argument list
bar<int, int>([](int x){ return x; }); // OK
}
foo 和 bar 之间的唯一区别是 foo 具有可变参数.编译器可以通过某种方式将lambda转换为 bar 中的std :: function.
The only difference between foo and bar is that foo has variadic arguments. Somehow the compiler is able to convert the lambda to a std::function in bar.
据我了解,模板类型推导不考虑类型转换.所以都不应该都失败吗?
To my understanding, template type deduction doesn't consider type conversions. So shouldn't both fail?
推荐答案
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
现在,foo<int,int>
是foo<ReturnT=int, ParamsT starts with {int}>
.
它没有完全指定ParamT
.实际上,没有办法完全指定ParamT
.
It does not fully specify ParamT
. In fact, there is no way to fully specify ParamT
.
作为不完整指定的模板,推导发生并且失败.它不会尝试如果我只是假设包装不会继续下去怎么办".
As an incompletely specified template, deduction occurs, and fails. It doesn't try "what if I just assume the pack doesn't go any further".
您可以通过以下方法解决此问题:
You can fix this with:
template<typename ReturnT, typename... ParamT>
void foo(block_deduction<std::function<ReturnT(ParamT...)>> callback)
{}
其中block_deduction
如下:
template<class T>
struct block_deduction_helper { using type=T; }:
template<class T>
using block_deduction = typename block_deduction_helper<T>::type;
现在推导被阻止在foo
的第一个参数上.
now deduction is blocked on foo
's first argument.
您的代码有效.
当然,如果您传入std::function
,它将不再自动推论参数.
Of course, if you pass in a std::function
it will no longer auto-deduce arguments.
请注意,推导类型擦除类型(如std::function
)的类型通常是代码异味.
Note that deducing the type of a a type erasure type like std::function
is usually code smell.
同时替换为:
template<class F>
void bar(F callback)
{}
如果必须获取参数,请使用函数特征助手(在SO上有很多).如果您只需要返回值,那么已经有std
个特征已经解决了.
if you must get arguments, use function traits helpers (there are many on SO). If you just need return value, there are std
traits that already work that out.
在c ++ 17 您可以执行以下操作:
In c++17 you can do this:
tempate<class R, class...Args>
void bar( std::function<R(Args...)> f ) {}
template<class F>
void bar( F f ) {
std::function std_f = std::move(f);
bar(std_f);
}
使用c ++ 17 演绎指南功能.
这篇关于如果模板没有可变参数,则将Lambda推导为std :: function的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!