将 lambda 函数传递给模板方法

发布于 2025-01-09 16:18:35 字数 1281 浏览 0 评论 0原文

我有以下模板化方法:

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);

I have the following templated 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)
{
}

And I have a function that looks like

  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);

However, I get a syntax error saying:

  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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嗫嚅 2025-01-16 16:18:35

函数调用尝试从第一个和第二个函数参数中推导出 T

它将从第一个参数正确推导 T,但无法从第二个参数推导它,因为第二个函数参数是 lambda 类型,而不是 std::function类型。

如果无法从推导上下文的所有参数进行推导,则推导失败。

您实际上不需要在这里从第二个参数/参数进行推导,因为 T 应该完全由第一个参数确定。因此,您可以将第二个参数设置为非推导上下文,例如使用 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_tstd::identity_type::type 的类型别名。留给范围解析运算符 :: 的所有内容都是非推导的上下文,这就是它起作用的原因。


如果您没有任何特殊原因在这里使用 std::function ,您也可以将任何可调用类型作为第二个模板参数:

template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)

这可以使用 lambda、函数指针、std::function 等作为参数。如果参数不可使用预期类型调用,则在包含调用的函数体实例化时将导致错误。您可以使用 SFINAE 或自 C++20 起的类型约束来在重载决策时强制执行此操作。

The function call tries to deduce T from both the first and second function parameter.

It will correctly deduce T from the first parameter, but fail to deduce it from the second parameter, because the second function argument is a lambda type, not a std::function type.

If deduction isn't possible from all parameters that are deduced context, deduction fails.

You don't really need deduction from the second parameter/argument here, since T should be fully determined by the first argument. So you can make the second parameter a non-deduced context, for example by using std::type_identity:

void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)

This requires C++20, but can be implemented easily in user code as well if you are limited to C++11:

template<typename T>
struct type_identity { using type = T; };

and then

void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)

std::identity_type_t<T> is a type alias for std::identity_type<T>::type. Everything left to the scope resolution operator :: is a non-deduced context, which is why that works.


If you don't have any particular reason to use std::function here, you can also just take any callable type as second template argument:

template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)

This can be called with a lambda, function pointer, std::function, etc. as argument. If the argument is not callable with the expected types, it will cause an error on instantiation of the function body containing the call. You can use SFINAE or since C++20 a type constraint to enforce this already at overload resolution time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文