当我使用具有接受另一个函数作为参数的模板函数时,C ++无法派生模板参数。一直指定它们很烦人。如何定义以下函数,而不必每次都指定类型参数?
#include <functional>
template <typename S, typename T>
T apply(const S& source, const function<T (const S&)>& f) {
return f(source);
}
template <typename S, class Functor, typename T>
T applyFun(const S& source, const Functor& f) {
return f(source);
}
int main() {
// Can't derive T. Why?
apply(1, [](int x) { return x + 1; });
// Compiles
apply<int, int>(1, [](const int& x) { return x + 1; });
// Can't derive T. Kind of expected.
applyFun(1, [](int x) { return x + 1; });
}
对我来说,为什么它不能在第二个函数中派生类型参数,却不能在第一个函数中派生类型(因为x + 1
是int
,所以应该推论{{1} }。
答案 0 :(得分:4)
模板参数必须出现在功能参数类型中才能扣除。此外,lambda不是函数,因此lambda的返回类型不能参与模板参数推导。
但是在这种情况下,无需指定返回类型。返回类型演绎可以完成这项工作:
template <typename S, class Functor>
auto applyFun(const S& source, const Functor& f) {
return f(source);
}
答案 1 :(得分:2)
如果您可以使用C ++ 17,则可以按照以下方式使用std::function
的推导指南
template <typename S, typename F,
typename T = typename decltype( std::function{std::declval<F>()} )::result_type>
T applyFun (S const & source, F const & f)
{
return f(source);
}
但是,正如Oliv所指出的,对于您的示例函数,不需要T
,因为您可以使用auto
(从C ++ 14;在C ++ 11中为auto ... -> decltype(f(source))
)。
-编辑-
OP说
此解决方案的优点是我可以在函数内部使用T(例如,如果我想实现vector_map)。
您也可以使用T
在函数内部检测并使用using
类似
template <typename S, typename F>
auto applyFun (S const & source, F const & f)
{
using T = typename decltype( std::function{f} )::result_type;
return f(source);
}
或更简单:using T = decltype( f(source) );
。
OP也观察到
缺点是由于某种原因,我现在无法在函数调用中编写
[] (const auto& x) { ... }
。
正确。
因为无法从通用lambda推断出std::function
模板类型。
但是根据您知道参数类型的事实,您可以再次使用decltype()
template <typename S, typename F,
typename T = decltype(std::declval<F const>()(std::declval<S const>()))>
T applyFun (S const & source, F const & f)
{ return f(source); }
此解决方案也应适用于C ++ 14和C ++ 11。