加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

带有可变参数模板和变量捕获的C 11“重载lambda”

发布时间:2020-12-16 06:50:23 所属栏目:百科 来源:网络整理
导读:我正在研究一种可能被称为“过载的lambda”的C 11习语: http://cpptruths.blogspot.com/2014/05/fun-with-lambdas-c14-style-part-2.html http://martinecker.com/martincodes/lambda-expression-overloading/ 使用可变参数模板重载n个函数似乎对我很有吸引
我正在研究一种可能被称为“过载的lambda”的C 11习语:

> http://cpptruths.blogspot.com/2014/05/fun-with-lambdas-c14-style-part-2.html
> http://martinecker.com/martincodes/lambda-expression-overloading/

使用可变参数模板重载n个函数似乎对我很有吸引力,但事实证明它不适用于变量捕获:任何[&] [=] [y] [& y](以及[this]等,如果在成员函数)导致编译失败:错误:不匹配调用'(overload< main(int,char **)::< lambda(int)&gt ;,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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读