c++ 中 lambda 的类型和大小
本文说明 c++11 lambda 生成一个匿名类,当没有 capture 到任何变量的时候, 大小几乎为零。其实是 1 byte ,因为 c++ 不允许 0 字节的结构体。
#include <iostream>
#include <functional>
#include <boost/type_index.hpp>
using namespace std;
template<typename T>
void show_type_and_size(T& x) {
cout << "T = "
<< boost::typeindex::type_id_with_cvr<T>().pretty_name() << ";\n"
<< boost::typeindex::type_id_with_cvr<decltype(x)>().pretty_name() << " x;\n"
<< "sizeof(x) " << sizeof(x) << "\n"
<< endl;
}
int main(int argc, char *argv[])
{
auto x = []() { cout << "hello world 1" << endl; };
auto y = []() { cout << "hello world 2" << endl; };
show_type_and_size(x);
show_type_and_size(y);
function<void(void)> fx = x;
show_type_and_size(fx);
return 0;
}
程序的输出结果
T = main::$_0;
main::$_0& x;
sizeof(x) 1
T = main::$_1;
main::$_1& x;
sizeof(x) 1
T = std::__1::function<void ()>;
std::__1::function<void ()>& x;
sizeof(x) 48
这里可以看到,每一个 lambda 有自己的匿名类,main::$_0
。
如果我们试图创建这样的对象
decltype(x) x1;
会有报错
cpp_src/cpp_lambda_size_type.cpp:21:17: error: no matching constructor for initialization of 'decltype(x)' (aka '(lambda at cpp_src/cpp_lambda_size_type.cpp:16:14)')
decltype(x) x1;
^
cpp_src/cpp_lambda_size_type.cpp:16:14: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
auto x = []() { cout << "hello world" << endl; };
^
cpp_src/cpp_lambda_size_type.cpp:16:14: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
1 error generated.
这说明这个匿名类是没有默认构造函数的,但是可以创建引用
decltype(x) & x1 = x;
x1();
decltype(y) & y1 = y;
y1();
而把 lambda 表达式赋值给一个 function 对象的时候,这个对象的大小就是 48 bytes 了。这是因为调用了
template< class F >
function::function( F f );
这个构造函数。
从这个角度上看,直接使用 lambda
,并且配合使用 auto
, decltype
,可以得到更加紧凑的函数对象。