如何将lambda(c ++ 11)传递给模板化函数? [英] How can I pass a lambda (c++11) into a templated function?

查看:70
本文介绍了如何将lambda(c ++ 11)传递给模板化函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在gcc 4.6.2中使用lambda函数,并想实现一个模板化的地图函数,如下所示:

I'm playing around with lambda functions in gcc 4.6.2, and would like to implement a templated "map" function like this:

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

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

This doesn't work, because the test code:

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

如果我删除模板并直接使用向量,则可以正常编译:

If I remove the templating, and use a vector directly, it compiles fine:

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

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

so it must be a problem with the way I'm defining the template.

以前有人遇到过吗?我知道lambda是令人难以置信的新事物。

Has anyone run into this before? I know lambdas are incredibly new.

推荐答案

问题是编译器无法弄清楚对B使用什么。为了确定要使用该函数的类型,您可以为 f 传入,但不要直接传递std :: function<>。您传入希望用于构造函数的内容。为了进行隐式构造,需要知道参数的类型。因此,您具有这种循环依赖关系,其中参数的类型取决于您传入的内容,但传入的内容取决于参数的类型。

The problem is that the compiler can't figure out what to use for B. In order to determine that type it wants to use the function<> you pass in for f, but you don't pass an std::function<> directly. You pass in something you expect to be used to construct a function<>. And in order to do that implicit construction it needs to know the type of argument. So you've got this circular dependency where the type of argument depends on what you pass in, but what gets passed in depends on the type of argument.

您可以中断通过指定模板参数(例如 map_< int,int>(list,[](int x)-> char {return x + 1;});

You can break this circular dependency by specifying the template parameters, such as map_<int,int>(list, [](int x) -> char { return x + 1; });

(尽管我看到函子实际上返回一个char而不是一个int,所以如果类型推导对您有用,您将获得一个 vector< char> 将结果分配给时无法转换为 vector< int>

(although I see the functor actually returns a char, not an int, so if the type deduction worked for you here you'd be getting back a vector<char> which cannot be converted to a vector<int> when you assign the result to transformed)

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

However as has been pointed out, generally templates take functors as just a plain template type:

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 ,除非返回类型随后出现,否则该表达式不可用。)

(we use the trailing return type because we need to use the expression f in the return type, which isn't available unless the return type comes afterwards.)

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

This allows the template to deduce the functor type directly and avoids any type conversions and best allows for optimization.

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

It's also customary to use iterators as arguments on these sorts of functions, in which case your function is just a wrapper around std::transform, so you can just use that directly. I'm not sure there's a whole lot of value in a special version that deals with vectors specifically.

这篇关于如何将lambda(c ++ 11)传递给模板化函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆