C++ Lambda表达式的类型是什么

问题描述

我的一个类的接口中需要传入一个回调函数,我想在这个回调函数中捕获外部变量,

但是这个类是我自己写的库,而这个外部变量并不是这个接口必要的参数,所以不能直接把外部变量传入接口中,

所以我想这个回调函数传入个lambda表达式,在lambda表达式中捕获外部变量,

请问在函数的参数列表中怎么声明这个回调函数的类型?

Lambda表达式类型的实验

如果我使用auto,当我把鼠标移到变量名上面时,看不出变量的类型:

img

它显示的类型是 (lambda at ***.cpp:353:14)

如果使用声明函数指针的方式声明lambda表达式,并不会报错

int (*callback)() = [] () { return 0; };

当我在Lambda表达式中捕获外部变量时就会报错:

int index = 0;
int (*callback)() = [index] () { return index; };

报错信息:

mainwindow.cpp:353:11: error: no viable conversion from '(lambda at ***/mainwindow.cpp:353:18)' to 'int (*)()'

img

可是我在回调函数中要使用外部变量。

问题

请问在函数参数列表中如何声明该回调函数的类型?
或者有什么其他的解决方式?

lambda是一种匿名函数类型。
没有捕获时,它会被处理成普通函数,所以隐式转换成函数指针。
有捕获时,它会被处理成匿名类对象成员方法,所以不能隐式转换成函数指针。

运算符重载
参考:https://en.cppreference.com/w/cpp/language/operators

如上参考链接,运算符重载大致有这样几种:

其中 operator type 有些特殊,涉及到转换函数,不需要加 return type,见下。

转换函数
见我的笔记:https://blog.csdn.net/weixin_47652005/article/details/118856689

简单测试例子:

#include

class Conv2int
{
public:
operator int() const
{
return 10;
}
};

int main()
{
Conv2int my_int;
std::cout << my_int * 5 << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
不带 captures 的 lambda
通过网站:https://cppinsights.io/

C++ 中的 Lambda 表达式
pdf

0星
超过10%的资源
401KB

下载

简单的测试:

#include

int main()
{
auto f = [](int a){std::cout << a << std::endl; return a;};
}
1
2
3
4
5
6
结果:

#include

int main()
{

class __lambda_5_12
{
public:
inline /*constexpr */ int operator()(int a) const
{
std::cout.operator<<(a).operator<<(std::endl);
return a;
}

using retType_5_12 = int (*)(int);
inline /*constexpr */ operator retType_5_12 () const noexcept
{
  return __invoke;
};

private: 
static inline int __invoke(int a)
{
  std::cout.operator<<(a).operator<<(std::endl);
  return a;
}

};

__lambda_5_12 f = __lambda_5_12{};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
可以看到,通过 operator type 的方式,可以将这个类给转换成一个 type ,这里的 type 就是这个函数指针。

带 captures 的 lambda
一旦加了capture,就不像刚才那样可以直接转为一个函数指针了:

#include

int main()
{
int b = 0;
auto f = [&b](int a){std::cout << a << std::endl; return a;};
}
1
2
3
4
5
6
7
网站解析如下:

#include

int main()
{
int b = 0;

class __lambda_6_12
{
public:
inline /*constexpr */ int operator()(int a) const
{
std::cout.operator<<(a).operator<<(std::endl);
return a;
}

private: 
int & b;

public:
__lambda_6_12(int & _b)
: b{_b}
{}

};

__lambda_6_12 f = __lambda_6_12{b};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
可以看到,其变成了一个彻彻底底的仿函数。
————————————————
版权声明:本文为CSDN博主「亲亲老婆几」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47652005/article/details/122400632运算符重载
参考:https://en.cppreference.com/w/cpp/language/operators

如上参考链接,运算符重载大致有这样几种:

其中 operator type 有些特殊,涉及到转换函数,不需要加 return type,见下。

转换函数
见我的笔记:https://blog.csdn.net/weixin_47652005/article/details/118856689

简单测试例子:

#include

class Conv2int
{
public:
operator int() const
{
return 10;
}
};

int main()
{
Conv2int my_int;
std::cout << my_int * 5 << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
不带 captures 的 lambda
通过网站:https://cppinsights.io/

C++ 中的 Lambda 表达式
pdf

0星
超过10%的资源
401KB

下载

简单的测试:

#include

int main()
{
auto f = [](int a){std::cout << a << std::endl; return a;};
}
1
2
3
4
5
6
结果:

#include

int main()
{

class __lambda_5_12
{
public:
inline /*constexpr */ int operator()(int a) const
{
std::cout.operator<<(a).operator<<(std::endl);
return a;
}

using retType_5_12 = int (*)(int);
inline /*constexpr */ operator retType_5_12 () const noexcept
{
  return __invoke;
};

private: 
static inline int __invoke(int a)
{
  std::cout.operator<<(a).operator<<(std::endl);
  return a;
}

};

__lambda_5_12 f = __lambda_5_12{};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
可以看到,通过 operator type 的方式,可以将这个类给转换成一个 type ,这里的 type 就是这个函数指针。

带 captures 的 lambda
一旦加了capture,就不像刚才那样可以直接转为一个函数指针了:

#include

int main()
{
int b = 0;
auto f = [&b](int a){std::cout << a << std::endl; return a;};
}
1
2
3
4
5
6
7
网站解析如下:

#include

int main()
{
int b = 0;

class __lambda_6_12
{
public:
inline /*constexpr */ int operator()(int a) const
{
std::cout.operator<<(a).operator<<(std::endl);
return a;
}

private: 
int & b;

public:
__lambda_6_12(int & _b)
: b{_b}
{}

};

__lambda_6_12 f = __lambda_6_12{b};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
可以看到,其变成了一个彻彻底底的仿函数。
————————————————
版权声明:本文为CSDN博主「亲亲老婆几」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47652005/article/details/122400632

这里有详解,应该能帮到你

lambda的类型实际上是一种类,这一点你从typeid([]{}).name()上能看出来。而且参数和返回值类型不相同的lambda表达式的类型也不同。这种类是系统自定义的,你无需实现,而这种类又重载了到函数指针的强制类型转换运算符,使得它看上去是个函数指针,其实不是的。