如果模板没有可变参数,则 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 转换为 std::function in bar.
据我了解,模板类型推导不考虑类型转换。那么不应该都失败吗?
bar
的类型参数没有任何推导,它们是完全指定的。
您在 foo
中仍有尾部要推断,但失败了,因为 lambda 不是 std::function
。
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
现在,foo<int,int>
是 foo<ReturnT=int, ParamsT starts with {int}>
。
它没有完全说明 ParamT
。其实没有办法完全指定ParamT
.
作为未完全指定的模板,推演发生,推演失败。它不会尝试 "what if I just assume the pack doesn't go any further".
您可以通过以下方式解决此问题:
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
的第一个参数的推导被阻止。
并且您的代码有效。
当然,如果你传入一个std::function
,它将不再自动推导参数。
请注意,推断像 std::function
这样的 a 类型擦除类型的类型通常是代码味道。
将两者替换为:
template<class F>
void bar(F callback)
{}
如果您必须获取参数,请使用函数特征助手(SO 上有很多)。如果您只需要 return 值,std
特征已经可以解决这个问题。
在c++17中你可以这样做:
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 推理指南功能。
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 转换为 std::function in bar.
据我了解,模板类型推导不考虑类型转换。那么不应该都失败吗?
bar
的类型参数没有任何推导,它们是完全指定的。
您在 foo
中仍有尾部要推断,但失败了,因为 lambda 不是 std::function
。
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
现在,foo<int,int>
是 foo<ReturnT=int, ParamsT starts with {int}>
。
它没有完全说明 ParamT
。其实没有办法完全指定ParamT
.
作为未完全指定的模板,推演发生,推演失败。它不会尝试 "what if I just assume the pack doesn't go any further".
您可以通过以下方式解决此问题:
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
的第一个参数的推导被阻止。
并且您的代码有效。
当然,如果你传入一个std::function
,它将不再自动推导参数。
请注意,推断像 std::function
这样的 a 类型擦除类型的类型通常是代码味道。
将两者替换为:
template<class F>
void bar(F callback)
{}
如果您必须获取参数,请使用函数特征助手(SO 上有很多)。如果您只需要 return 值,std
特征已经可以解决这个问题。
在c++17中你可以这样做:
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 推理指南功能。