C++ 如何将lambda(c+;+;11)传递到模板化函数中?

C++ 如何将lambda(c+;+;11)传递到模板化函数中?,c++,lambda,c++11,C++,Lambda,C++11,我正在使用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::t

我正在使用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;
}
template std::vector map(常量std::vector&orig,常量std::function f){
std::向量rv;
rv.调整大小(原始大小());
转换(开始(原点)、结束(原点)、开始(rv)、f);
返回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;
}
int main(int argc,char**argv){
std::向量表;
列表。推回(10);
列表。推回(20);
列表。推回(50);
std::vector transformed=map(列表,[](int x)->int{return x+1;});
std::for_each(begin(transformed)、end(transformed),[](intx){printf(“->%d\n”,x);});
返回0;
}
给出此错误:

test.cpp:49:80:错误:调用“map(std::vector&,main(int,char**):)”时没有匹配的函数
测试cpp:49:80:注:候选人为:
test.cpp:6:49:注意:模板std::vector映射(const std::vector&,std::function)
如果我删除模板,并直接使用向量,它编译得很好:

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;
}
std::vector map(常量std::vector&orig,常量std::function f){
std::向量rv;
rv.调整大小(原始大小());
转换(开始(原点)、结束(原点)、开始(rv)、f);
返回rv;
}
所以我定义模板的方式肯定有问题


以前有人碰到过这个吗?我知道lambda非常新。

您不需要使用std::function。只需将谓词参数设置为模板值。比如说,

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

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

 }
#包括
#包括
#包括
#包括
模板
结构图{
类型定义C(*F)(常数T&);
std::向量rv;
映射(){}
映射(常量标准::向量&o,F){
rv.调整大小(o.大小());
std::transform(o.begin()、o.end()、rv.begin()、f);
}
~map(){}
运算符std::vector()常量{
返回rv;
}
};
int main(){
std::向量asd(5,12);
std::vector transformed=map(asd,[](const int&x)->char{return x+1;});
std::copy(transformed.begin()、transformed.end()、std::ostream_迭代器(std::cout“”);
}

问题是编译器无法确定B使用什么。为了确定该类型,它希望使用您为
f
传入的函数,但您不直接传递std::函数。您传入了一些您希望用于构造函数的内容。为了进行隐式构造,它需要知道参数的类型。所以我们有一个循环依赖关系,参数的类型取决于传入的内容,但传入的内容取决于参数的类型

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

(虽然我看到函子实际上返回的是一个字符,而不是一个int,因此如果类型推断在这里对您起作用,您将得到一个
向量
,当您将结果分配给
转换后的
时,它无法转换为
向量

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

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;
    /*...*/
}
模板
自动映射(常量std::vector&orig,Func f)->std::vector{
std::向量rv;
/*...*/
}
(我们使用尾部返回类型,因为我们需要在返回类型中使用表达式
f
,除非返回类型在后面出现,否则表达式不可用。)

这允许模板直接推断函子类型,避免任何类型转换,并最好允许优化


在这类函数中,通常使用迭代器作为参数,在这种情况下,您的函数只是std::transform的包装器,因此您可以直接使用它。我不确定在专门处理向量的特殊版本中是否有很多值。

假设您打算添加一个新的“typename C”对模板,并使参数“cf”,这有同样的问题。它不认为“映射”函数匹配。您知道,在您文章中的示例中,您在调用
map
时定义了函数
map
?请注意调用中的下划线…:-)很抱歉输入错误--我从一个文件中粘贴了此函数,尝试了十几次,以查看是否可以让编译器更好地了解它没有做什么柯。我想我现在已经修好了。这很有效!(我修好了“char”的东西;对此很抱歉。)因此,听起来我遗漏了两点:1.lambda不是函数类型,而是使用隐式构造函数转换的。2.标记lambda类型的唯一真正方法是decltype,lambda实际上没有任何其他方式可以被描述为类型。同意示例的无意义的具体性——我只是想看看这完全可以做到,而且可以!谢谢你的帮助!这个问题的答案有一个类型特征,它使用可变模板,这使得询问lambda的类型更容易。例如,你可以用它来表示
函数\u特征::结果\u类型
。如果a没有损坏,我的decltype也不起作用t可构造。
decltype(f(orig[0])
是另一种选择。