将 lambda 函数传递给模板方法
Passing a lambda function to a template method
我有以下模板化方法:
auto clusters = std::vector<std::pair<std::vector<long>, math::Vector3f>>
template<class T>
void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
{
}
我有一个函数看起来像
auto comp1 = [&](
const std::pair<std::vector<long>, math::Vector3f>& n1,
const std::pair<std::vector<long>, math::Vector3f>& n2
) -> int {
return 0;
};
math::eraserFunction(clusters, comp1);
但是,我收到一个语法错误:
116 | void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
| ^~~~~~~~~~~~~~
core.hpp:116:6: note: template argument deduction/substitution failed:
geom.cpp:593:23: note: 'math::method(const at::Tensor&, const at::Tensor&, int, float, int, int, float)::<lambda(const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&, const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&)>' is not derived from 'std::function<int(const T&, const T&)>'
593 | math::eraserFunction(clusters, comp1);
函数调用试图从第一个和第二个函数参数中推导出 T
。
它会从第一个参数正确推导T
,但从第二个参数推导失败,因为第二个函数参数是lambda类型,而不是std::function
类型。
如果无法从推导上下文的所有参数中推导,则推导失败。
这里你真的不需要从第二个 parameter/argument 中推导,因为 T
应该完全由第一个参数决定。因此,您可以使第二个参数成为 non-deduced 上下文,例如使用 std::type_identity
:
void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)
这需要 C++20,但如果您仅限于 C++11,也可以在用户代码中轻松实现:
template<typename T>
struct type_identity { using type = T; };
然后
void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)
std::identity_type_t<T>
是 std::identity_type<T>::type
的类型别名。范围解析运算符 ::
剩下的所有内容都是 non-deduced 上下文,这就是它起作用的原因。
如果你没有任何特别的理由在这里使用 std::function
,你也可以将任何可调用类型作为第二个模板参数:
template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)
这可以用 lambda、函数指针、std::function
等作为参数调用。如果参数不能用预期的类型调用,它将导致包含调用的函数体的实例化错误。您可以使用 SFINAE 或自 C++20 起在重载解析时使用类型约束来强制执行此操作。
我有以下模板化方法:
auto clusters = std::vector<std::pair<std::vector<long>, math::Vector3f>>
template<class T>
void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
{
}
我有一个函数看起来像
auto comp1 = [&](
const std::pair<std::vector<long>, math::Vector3f>& n1,
const std::pair<std::vector<long>, math::Vector3f>& n2
) -> int {
return 0;
};
math::eraserFunction(clusters, comp1);
但是,我收到一个语法错误:
116 | void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
| ^~~~~~~~~~~~~~
core.hpp:116:6: note: template argument deduction/substitution failed:
geom.cpp:593:23: note: 'math::method(const at::Tensor&, const at::Tensor&, int, float, int, int, float)::<lambda(const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&, const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&)>' is not derived from 'std::function<int(const T&, const T&)>'
593 | math::eraserFunction(clusters, comp1);
函数调用试图从第一个和第二个函数参数中推导出 T
。
它会从第一个参数正确推导T
,但从第二个参数推导失败,因为第二个函数参数是lambda类型,而不是std::function
类型。
如果无法从推导上下文的所有参数中推导,则推导失败。
这里你真的不需要从第二个 parameter/argument 中推导,因为 T
应该完全由第一个参数决定。因此,您可以使第二个参数成为 non-deduced 上下文,例如使用 std::type_identity
:
void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)
这需要 C++20,但如果您仅限于 C++11,也可以在用户代码中轻松实现:
template<typename T>
struct type_identity { using type = T; };
然后
void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)
std::identity_type_t<T>
是 std::identity_type<T>::type
的类型别名。范围解析运算符 ::
剩下的所有内容都是 non-deduced 上下文,这就是它起作用的原因。
如果你没有任何特别的理由在这里使用 std::function
,你也可以将任何可调用类型作为第二个模板参数:
template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)
这可以用 lambda、函数指针、std::function
等作为参数调用。如果参数不能用预期的类型调用,它将导致包含调用的函数体的实例化错误。您可以使用 SFINAE 或自 C++20 起在重载解析时使用类型约束来强制执行此操作。