带有可变参数模板和变量捕获的C 11“重载lambda”
我正在研究一种可能被称为“过载的lambda”的C 11习语:
> http://cpptruths.blogspot.com/2014/05/fun-with-lambdas-c14-style-part-2.html 使用可变参数模板重载n个函数似乎对我很有吸引力,但事实证明它不适用于变量捕获:任何[&] [=] [y] [& y](以及[this]等,如果在成员函数)导致编译失败:错误:不匹配调用'(overload< main(int,char **)::< lambda(int)> ;,main(int,char **)::< lambda(char *)>>)(char *&)'(使用我的本地GCC 4.9.1和ideone.com GCC 5.1) 另一方面,固定的2-ary情况没有遇到这个问题. (尝试将第一个#if 0更改为ideone.com上的#if 1) 关于这里发生了什么的任何想法?这是编译器错误,还是我偏离了C 11/14规范? http://ideone.com/dnPqBF #include <iostream> using namespace std; #if 0 template <class F1,class F2> struct overload : F1,F2 { overload(F1 f1,F2 f2) : F1(f1),F2(f2) { } using F1::operator(); using F2::operator(); }; template <class F1,class F2> auto make_overload(F1 f1,F2 f2) { return overload<F1,F2>(f1,f2); } #else template <class... Fs> struct overload; template <class F0,class... Frest> struct overload<F0,Frest...> : F0,overload<Frest...> { overload(F0 f0,Frest... rest) : F0(f0),overload<Frest...>(rest...) {} using F0::operator(); }; template <> struct overload<> { overload() {} }; template <class... Fs> auto make_overload(Fs... fs) { return overload<Fs...>(fs...); } #endif #if 0 #define CAP #define PRINTY() #else #define CAP y #define PRINTY() cout << "int y==" << y << endl #endif int main(int argc,char *argv[]) { int y = 123; auto f = make_overload( [CAP] (int x) { cout << "int x==" << x << endl; PRINTY(); },[CAP] (char *cp) { cout << "char *cp==" << cp << endl; PRINTY(); }); f(argc); f(argv[0]); } 解决方法
重载解析仅适用于公共范围中存在的函数.这意味着第二个实现无法找到第二个重载,因为您没有从重载< Frest ...>导入函数调用操作符.过载< F0,Frest ......>.
但是,非捕获lambda类型将转换运算符定义为具有与lambda函数调用运算符相同的签名的函数指针.可以通过名称查找找到此转换运算符,这是在删除捕获部分时调用的内容. 正确的实现,适用于捕获和非捕获lambdas,并始终调用operator()而不是转换运算符,应如下所示: template <class... Fs> struct overload; template <class F0,overload<Frest...> { overload(F0 f0,overload<Frest...>(rest...) {} using F0::operator(); using overload<Frest...>::operator(); }; template <class F0> struct overload<F0> : F0 { overload(F0 f0) : F0(f0) {} using F0::operator(); }; template <class... Fs> auto make_overload(Fs... fs) { return overload<Fs...>(fs...); } DEMO 在c++17中,使用类模板参数推导和使用声明的包扩展,上面的实现可以简化为: template <typename... Ts> struct overload : Ts... { using Ts::operator()...; }; template <typename... Ts> overload(Ts...) -> overload<Ts...>; DEMO 2 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |