C ++ 11和缺乏多态lambdaexpression式 – 为什么?

我一直在审查C ++ 11标准的草案版本。 特别是关于lambda的章节,我对于不引入多态lambdaexpression式的理由感到困惑。

例如,在100001种方法中,可以使用多态lambdaexpression式,我希望我们可以使用如下的代码:

template<typename Container> void foo(Container c) { for_each(c.begin(), c.end(), [](T& t) { ++t; }); } 

原因是什么:

  • 委员会是否耗尽了时间?

  • 那个多态的lambdas太难实现了?

  • 或者也许他们被视为PTB不需要?

注意:请记住上面的例子不是唯一的,它只是作为代码types的指南。 仅仅专注于为上述代码提供解决方法的答案将不被视为有效!

相关资料:

  • 用于C ++的Lambdaexpression式和闭包 (文档编号N1968 = 06-0038)
  • lambda函数可以模板化吗?

我们没有多态lambdaexpression式的原因在本文中解释得很好。

它与从C ++ 11中抽取的概念特征有关:实质上,多态lambdaexpression式是普通的,无约束的函数模板,我们不知道如何对使用无约束模板的概念约束模板进行types检查。 但是,解决这个问题的过程很简单,如下图所示(死链接),所以我不认为有任何障碍。

链接到cpp-next是死的; 相关信息可以在这里find

由于参数c符合容器的STL要求,所以应该可以使用类似的东西

 template<typename Container> void foo(Container c) { for_each(c.begin(), c.end(),[](typename Container::reference t) { ++t; }); } 

我还将展示上面的John Purdy的注释,这是另一种在lambdaexpression式中获取所需types名称的方法:

 template<typename Container> void foo(Container c) { for_each(c.begin(),c.end(),[](decltype(*c.begin()) t) { ++t; }); } 

(是的,Dominar,我知道你不喜欢这个答案,因为它不能回答你的问题,但是我敢打赌下一个问这个问题的人会去寻找一个方法让他们的代码工作,所以在问题相关的地方有一些技巧是有意义的。)

这可能是因为已经有了这样的语法,lambdas的目的是引入一个更简单的语法来覆盖大多数情况。 当你试图覆盖所有的情况(如果你想让自动生成的仿函数inheritance特定的基类?),你就失去了lambda的比较优势(简单和简洁)。

我真的不喜欢所提出的语法。 T是关键字吗? 所有名称查找失败的标识符是否会自动变成模板types名参数? 这可以防止你发现拼写错误,国际海事组织是一个主意:

 for_each(c.begin(),c.end(),[](iterater& t) { ++t; }); // programmer misspelled "iterator" and now has a polymorphic lambda, oops 

它还引入了“远距离行为”行为,如果指定types在某个头文件中引入,则意义突然改变。 也真的很糟糕

那么,因为它应该创build一个模板,我们可以借用现有的语法:

 for_each(c.begin(),c.end(),[]template<typename T>(T& t) { ++t; }); 

这是明确的,现在允许非types的模板参数(对于通过引用接受数组很有用),但是实际上很难实现。 在这一点上,你最好用手写出函子,这会更容易理解。

不过,我认为一个简单的语法是可能的使用auto关键字:

 for_each(c.begin(),c.end(),[](auto& t) { ++t; }); 

下一节错误地假定模板参数出现在函数types而不是其operator()()

但现在你有一个问题, for_each推断一个types名模板参数,而不是模板模板参数。 在这种情况下,types推断是不可能的。

在当前的build议中, lambdaexpression式是types的 ,即使它是不可分注的(非decltype )types。 您必须失去该function才能在呼叫地点进行推理。

举例说明这个问题不是lambda的缺点,它只是一个不可推卸的上下文:

 #include <vector> #include <algorithm> #include <iterator> int main(void) { using namespace std; vector<int> a(10); vector<int> b(10); vector<int> results; transform(a.begin(), a.end(), b.begin(), back_inserter(results), min<int>); } 

必须明确指定std::min的模板types参数。 在这方面,Lambdas与使用现有的函子并没有什么不同。

编辑:好吧,现在我意识到我们不是build议lambda生成模板仿函数types,但实现模板函数应用操作符( operator()() )的单个非模板函子types,我同意编译器应该能够产生这样的事情。 我build议在这里使用auto关键字是一个很好的简单语法来请求。

不过,我对auto也不是很满意。 什么有多个参数的lambdas:

 [](auto& x, auto& y){ return x + y; } //becomes template<typename T1, typename T2> auto operator()(T1& x, T2& y) -> decltype(x + y) { return x + y; } 

好的,这样做效果不错,但是如果我们需要两个参数但只有一个types参数呢?

 [](auto& x, decltype(x)& y){ return x + y; } //becomes template<typename T1> auto operator()(T1& x, T1& y) -> decltype(x + y) { return x + y; } 

似乎没关系,但我觉得语法有误导性。 语法表明,types参数是从第一个实际参数推断出来的,第二个参数被强制为相同的types,但实际上两个实际参数在types推断中被认为是相等的。

也许最好是这种情况被限制为每个types参数一个lambda参数,如果你想要更多的约束,可以自己编写函子。 在我看来,这是灵活性和权力之间的一个很好的折衷,而且保持简单的语法。

那么,现在你已经联系了n1968 ,你的问题的答案是明显的。 它在build议的第5.1节中find。

以下 (您对我上面的其他答案的评论)的作品:

 #include <algorithm> #include <vector> struct foo { template<typename T> void operator()(T& t) { ++t; } }; int main() { std::vector<int> v; std::for_each(v.begin (),v.end(),foo()); return 0; } 

但是以下不是:

 #include <algorithm> #include <vector> template<typename T> struct foo { void operator()(T& t) { ++t; } }; int main() { std::vector<int> v; std::for_each(v.begin (),v.end(),foo()); // <-- the syntax for foo here // is kinda fictitious return 0; } 

可能C ++委员会认为lambda比第一个更像第二个例子。 (虽然我还没有想出一个巧妙的方法来定义一个lambda,在这种情况下会有所作为,任何人都有疯狂的想法?)