C++ 在C+中实现干净的lambda函数+;11
我一直在使用新的C++11 lambda,而完全指定模板参数的要求是一个真正的阻力。我想使用的语法类似于以下内容:C++ 在C+中实现干净的lambda函数+;11,c++,templates,lambda,c++11,C++,Templates,Lambda,C++11,我一直在使用新的C++11 lambda,而完全指定模板参数的要求是一个真正的阻力。我想使用的语法类似于以下内容: #include <vector> #include <algorithm> struct foo { void bar() {} }; int main() { vector<foo> v(10); for_each(v.begin(), v.end(), [](f) {f.bar();});
#include <vector>
#include <algorithm>
struct foo
{
void bar() {}
};
int main()
{
vector<foo> v(10);
for_each(v.begin(), v.end(), [](f) {f.bar();});
^^^
}
std::array<int,10> a;
for_each(begin(a),end(a),[](auto i){ /* ... */ });
然后,您可以使用一些模板和预处理器魔法来生成
\u a
和组合
,但当您的名称不明确时(例如,第三个结构带有b()
函数-您需要一种消除歧义的方法,这是我目前无法想到的。如果您愿意使用宏并使用所有这些设置,那么使用decltype的快捷宏就不够了吗?例如:
#define T_FOR_EACH( begin_, end_, var_, func_ ) \
for_each( (begin_), (end_), [](decltype(*begin_) var_) func_ )
那么你可以:
T_FOR_EACH(x.begin(), x.end(), &f, {f->f();} );
我没有在define中为变量添加&
的原因是,使用这种格式,您仍然可以指定您想要的所有类型说明符,以及它是引用还是副本
如果语法错误,请原谅,我周围没有C++11编译器,我可以用它来测试任何一个,这只是一个想法。注意:我完全同意[](auto f){…}
将是非常可取的
虽然我们没有,但是好的老式typedef
?它只增加了一行,非常“低技术”,并且使lambda易于阅读:
typedef const map<key_type, value_type>::value_type& λp_t;
for_each(m.begin(), m.end(), [&](λp_t x) {...});
typedef常量映射::value_type&λp_t;
对于每个(m.begin(),m.end(),[&](λp_t x){…});
您可以使用decltype:
for_each(m.begin(), m.end(), [&](decltype(*m.begin()) x){...});
transform(begin(a),end(a),begin(a),[](decltype(*begin(a)) i) { return 2*i; });
但它真的,真的很糟糕,你不能在匿名lambdas使用自动
更新:
你也可以这样做
#define _A(CONTAINER_NAME) decltype(*CONTAINER_NAME.begin())
for_each(m.begin(), m.end(), [&](_A(m) x) { ... });
因此,假设在以下情况下:
#include <vector>
#include <algorithm>
struct foo
{
void bar() {}
};
int main()
{
vector<foo> v(10);
for_each(v.begin(), v.end(), [](f) {f.bar();});
^^^
}
std::array<int,10> a;
for_each(begin(a),end(a),[](auto i){ /* ... */ });
问题是lambda的类型会影响每个模板实例化的类型,这可能会选择不同的专门化,这反过来可能需要对lambda参数进行不同的类型推断。因此编译器根本没有合理的方法使用算法代码自动推断你传递的论点
无论如何,至少对于for_-each算法,您不需要这样做,只需使用循环的范围:
for(auto i:a) { /* ... */ }
在其他地方使用decltype:
for_each(m.begin(), m.end(), [&](decltype(*m.begin()) x){...});
transform(begin(a),end(a),begin(a),[](decltype(*begin(a)) i) { return 2*i; });
您可以让lambda从函数中推断出它的参数(和类型),但每个函数都必须使其可用。这里讨论了如何实现这一点: 基本上,您可以使用类似ruby的方式调用函数。因此,您可以对每个函数调用
,如下所示:
$(for_each(some_range), x)
{
printf("%i\n", x);
};
美元符号($)是一个宏,负责从函数中推断类型。现在这不适用于std::for_each
,它必须与一个专门定义的函数一起使用,该函数发出lambda的参数类型
由于它使用宏,因此不考虑运算符优先级,因此不能将其与范围适配器一起使用。因此这将编译
#define FOR_EACH_IN(iter__, list__, ...) \
std::for_each(list__.begin(), list__.end(), [&](decltype(*list__.begin()) iter__) __VA_ARGS__)
鉴于:
auto DoSomethingTo = [](T AnElement){ /* insert profitable activity */ };
std::array<T, n> AnArray;
<> P>我内心的JavaScript迷是多么兴奋,但是作为一个C++程序员,我很害怕出现这样的事情。它可能会跳过很多静态分析和LTENS,加上出错的时候,我希望你喜欢调试宏。
但是,嘿,它很干净。我想你可以使用const decltype(v)::value_type&f
对于很长的类型可能会更短。很遗憾,我们使用auto
作为参数类型。无论如何,你添加的这些废话在我看来都是粗俗和糟糕的做法。你是说你这么做是为了删掉一个字符吗?每个(x.begin(),x.end(),[](foo f){f->f();;
(a)因为它将算法与所使用的数据类型联系得更少,(b)因为编译器可以计算出类型,因此应该,和(c)因为当类型变得复杂时,它开始节省更多,并大大减少了行混乱和样板文件:对于每个(x.begin(),x.end(),[&](const first_type&a,const second_type&b){return a+b;}
与对每一个(x.begin(),x.end(),[](a,b){return a+b;}
节省了近40个字符!或者当您开始对映射进行操作时,对每一个(m.begin(),m.end(),[&](const map::value_type&x){…}与对每一个(m.begin(),m.end(),[&](x){…}<代码> >背景信息:Habor萨特说C++委员会考虑添加“AutoCo”。作为一种参数类型,正是出于这个原因。然而,他们得出结论,普通函数也必须支持这一点。因为他们担心如此巨大的变化,特别是在C++11开发后期,会延迟整个标准,所以他们完全忽略了这一点。我不会说他们是白痴,但我想知道在C++中,AutoLAMBDA的问题是,它会使lambda对象本身具有多态性,但是在C++中,任何对象(表达式)都必须有一个定义良好的编译器时间类型。如果我写的话,应该发生什么:<代码> AutoLabda=[A](AutoX){ReX;};lambda(1);lambda(“fo”)。
?也许它可以解析为一个模板操作符()(tx)
或其他什么?但是委员会现在对包含没有任何实际经验的复杂功能(概念、异常规范、外部模板)持谨慎态度罗德里戈:我明白你的意思,但是,他们可以让匿名的lambda与AutoWork一起工作,因为这会使语言变得更加方便。让我们面对它,原因是C++不再慢慢地消失,因为它们似乎从来没有结合对大多数C++程序员有用的功能。@ ViktorSehr,但是你必须定义什么是一个匿名lambda是。然后,解析auto
类型的规则…请记住,当前auto
仅可用于自动(本地)变量,而不可用于函数参数。我认为lambda模板更可行:用于每个(m.begin(),m.end(),template[](tx){…})
。这真的很不公平。委员会非常希望看到C++11中的多态lambda,它们被包括在原始提案及其几次修订中。不幸的是