如何让C ++从Lambda推断模板类型参数?

问题描述

这是我的代码:

#include<iostream>

struct Item {
  int val;
};

struct XItem {
  int val;
};

void transform(const Item &i,XItem &target) {
  target.val = i.val;
}

template<typename T>
void show(const T &v) {
  std::cout << v.val << std::endl;
}

template<typename ParamsType,typename ResultType>
void handleRequest(Item &cur,ResultType (*impl)(const ParamsType &p)) {
  ParamsType p{};
  transform(cur,p);
  ResultType res = (*impl)(p);
  show(res);
}

struct ResItem {
  int val;
};

int main(int argc,char *argv[]) {
  Item i{42};
  handleRequest(i,[](const XItem &x) {
    return ResItem{x.val};
  });
  return 0;
}

编译它会出现以下错误:

test.cpp:33:3: error: no matching function for call to 'handleRequest'
  handleRequest(i,[](const XItem &x) {
  ^~~~~~~~~~~~~
test.cpp:21:6: note: candidate template ignored: could not match 'ResultType
      (*)(const ParamsType &)' against '(lambda at test.cpp:33:20)'
void handleRequest(Item &cur,ResultType (*impl)(const ParamsType &p)) {
     ^

我不确定为什么会发生这种情况,但是我确实怀疑,因为lambda虽然可以隐式转换为,但它不是一个,所以无法从中推导出模板参数

我尝试改用std::function<ResultType(const ParamsType &p)>,这也不起作用。 This question详细说明了问题,因此我尝试使用其解决方案:

template<typename ParamsType,typename ResultType,typename Callback>
void handleRequest(Item &cur,Callback cb) {
  ParamsType p = transform(cur);
  ResultType res = std::invoke(cb,p);
  show(res);
}

但是,现在ParamsTypeResultType不能从回调中隐式推导出,我需要显式地给它们。但是我真的想推断ResultType,因为在实际代码中,它可能会很长(它是从lambda return语句推断出来的,该语句比这个最小的示例更复杂)。我需要这两种类型,因为transformshow都被重载,并且需要绑定类型。

在这种情况下是否可以让handleRequest推断这些类型?如果是,怎么办?

解决方法

问题在于,template argument deduction中未考虑隐式转换(从lambda到函数指针),这无法推断出模板参数。

类型推导不考虑隐式转换(上面列出的类型调整除外):这是overload resolution的工作,以后会发生。

您可以显式指定模板参数以绕过推论,

handleRequest<XItem,ResItem>(i,[](const XItem &x) {
  return ResItem{x.val};
});

或将lambda显式转换为函数指针,

handleRequest(i,static_cast<RestItem(*)(const XItem&)>([](const XItem &x) {
  return ResItem{x.val};
}));

或使用operator+将lambda转换为函数指针。

handleRequest(i,+[](const XItem &x) {
  return ResItem{x.val};
});

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...