繁体   English   中英

如何将lambda(c ++ 11)传递给模板化函数?

[英]How can I pass a lambda (c++11) into a templated function?

我正在使用gcc 4.6.2中的lambda函数,并希望实现模板化的“map”函数,如下所示:

template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, const std::function<B(A)> f) {
  std::vector<B> rv;
  rv.resize(orig.size());
  std::transform(begin(orig), end(orig), begin(rv), f);
  return rv;
}

这不起作用,因为测试代码:

int main(int argc, char **argv) {
  std::vector<int> list;
  list.push_back(10);
  list.push_back(20);
  list.push_back(50);

  std::vector<int> transformed = map(list, [](int x) -> int { return x + 1; });
  std::for_each(begin(transformed), end(transformed), [](int x) { printf("-> %d\n", x); });
  return 0;
}

给出了这个错误:

test.cpp:49:80: error: no matching function for call to ‘map(std::vector<int>&, main(int, char**)::<lambda(int)>)’
test.cpp:49:80: note: candidate is:
test.cpp:6:49: note: template<class A, class B> std::vector<B> map(const std::vector<A>&, std::function<B(A)>)

如果我删除模板,并直接使用向量,它编译很好:

std::vector<int> map(const std::vector<int>& orig, const std::function<int(int)> f) {
  std::vector<int> rv;
  rv.resize(orig.size());
  std::transform(begin(orig), end(orig), begin(rv), f);
  return rv;
}

所以我定义模板的方式一定是个问题。

有没有人遇到过这个? 我知道lambdas是非常新的。

您不需要使用std :: function。 只需将谓词参数设为模板值即可。 例如,

template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {

std :: function <>作为成员值类型或用于定义非模板化代码更有用。

我也在处理lambdas,我注意到你可以在函数定义的参数列表中声明一个函数指针,当你调用该函数时,如果它与函数原型匹配,你可以传递一个lambda表达式作为参数。

#include <iostream>

#include <vector>

#include <algorithm>

#include <iterator>



template <typename T,typename C>

struct map  {

   typedef C (*F)(const T&);

   std::vector<C> rv;

   map () {}

   map (const std::vector<T>& o,F f)  {

      rv.resize(o.size());

      std::transform (o.begin(),o.end(),rv.begin(),f);

    }

   ~map () {}

   operator std::vector<C> () const  {

      return rv;

    }

 };



int main ()  {

   std::vector<int> asd(5,12);

   std::vector<char> transformed=map<int,char>(asd,[](const int& x)->char {return x+1;});

   std::copy (transformed.begin(),transformed.end(),std::ostream_iterator<int>(std::cout," "));

 }

问题是编译器无法弄清楚要用于B的内容。为了确定该类型它想要使用函数<>你传入f ,但是你没有传递一个std :: function <>直。 你传递了你期望用来构造函数<>的东西。 并且为了进行隐式构造,它需要知道参数的类型。 所以你有这个循环依赖,其中参数的类型取决于你传入的内容,但传入的内容取决于参数的类型。

您可以通过指定模板参数来破坏此循环依赖关系,例如map_<int,int>(list, [](int x) -> char { return x + 1; });

(虽然我看到仿函数实际上返回一个char,而不是一个int,所以如果类型推导在这里工作,你将得到一个vector<char> ,当你分配结果时,它不能转换为vector<int> transformed

但是正如已经指出的,通常模板将仿函数仅仅作为普通的模板类型:

template<typename A,typename Func>
auto map_(const std::vector<A>& orig, Func f) -> std::vector<decltype(f(A()))> {
    std::vector<decltype(f(A()))> rv;
    /*...*/
}

(我们使用尾部返回类型,因为我们需要在返回类型中使用表达式f ,除非之后返回类型,否则该表达式不可用。)

这允许模板直接推导出仿函数类型并避免任何类型转换,并且最好允许优化。

在这些函数中使用迭代器作为参数也是习惯,在这种情况下,你的函数只是std :: transform的包装器,所以你可以直接使用它。 我不确定在特殊版本中特别处理矢量有很多价值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM