将 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 起在重载解析时使用类型约束来强制执行此操作。