C++ 无法为高阶函数派生模板参数
C++ can't derive template parameters for high-order functions
当我使用接受另一个函数作为参数的 have 模板函数时,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
,所以它应该推断出 T = int
).
模板参数必须出现在函数参数类型中才能扣除。此外,lambda 不是函数,因此 return 类型的 lambda 不能参与模板参数推导。
但在这种情况下,不需要指定return类型。 Return 类型推导可以完成这项工作:
template <typename S, class Functor>
auto applyFun(const S& source, const Functor& f) {
return f(source);
}
如果可以使用 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;auto ... -> decltype(f(source))
在 C+ +11).
-- 编辑--
OP 说
The good thing about this solution is that I can use T inside the function (e.g. if I want to implement 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 还观察到
The downside is that for some reason now I can't write [] (const auto& x) { ... }
in function call.
正确。
因为 std::function
无法从泛型 lambda 中推导出模板类型。
但是使用你知道参数类型的事实,你可以再次使用 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。
当我使用接受另一个函数作为参数的 have 模板函数时,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
,所以它应该推断出 T = int
).
模板参数必须出现在函数参数类型中才能扣除。此外,lambda 不是函数,因此 return 类型的 lambda 不能参与模板参数推导。
但在这种情况下,不需要指定return类型。 Return 类型推导可以完成这项工作:
template <typename S, class Functor>
auto applyFun(const S& source, const Functor& f) {
return f(source);
}
如果可以使用 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;auto ... -> decltype(f(source))
在 C+ +11).
-- 编辑--
OP 说
The good thing about this solution is that I can use T inside the function (e.g. if I want to implement 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 还观察到
The downside is that for some reason now I can't write
[] (const auto& x) { ... }
in function call.
正确。
因为 std::function
无法从泛型 lambda 中推导出模板类型。
但是使用你知道参数类型的事实,你可以再次使用 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。