C++ lambda 作为类方法
C++ lambdas as class methods
作为一个假设的问题,我想使用lambda作为类方法。我知道这在专业背景下很糟糕,但无论如何我都很好奇。一个例子可能最适合展示我想做什么。下面是复数的基本类:
class Complex {
private:
double re, im;
public:
Complex() : re(0.0), im(0.0) {}
Complex(double re, double im) : re(re * 1.0), im(im * 1.0) {}
Complex(const Complex &c) = default;
~Complex() = default;
function<double(void)> getRe = [=]() -> double { return re; };
function<void(double)> setRe = [&](double re) -> void { this->re = re; };
function<double(void)> getIm = [=]() -> double { return im; };
function<void(double)> setIm = [&](double im) -> void { this->im = im; };
};
起初我尝试使用auto
而不是显式指定函数类型,但我收到错误,说我不能在非静态字段中使用auto
。
这似乎实际上有效,因为它显然产生了所需的行为。我已经使用它使用 OpenGL 绘制了一些分形,因此它最终做了一些相当密集的工作。
正如我所说,它似乎有效,我已经为setter使用了引用捕获,特别是因为我认为由于this
是对当前实例的引用,因此可能需要它,并且对于getters的值捕获,因为默认情况下标识符最终在类范围内搜索(在这种情况下)并找到字段。
我有两个问题:
我还没有用Visual Studio对此进行测试,但是在我正在使用的CLion和MSVC编译器中,
this
被突出显示为不存在的变量(即使它"有效")。知道为什么会这样吗?课程最终变得缓慢。就像慢了一个数量级以上一样。当我使用像
double getRe() {return re;}
这样的普通 getter 和 setter 时,渲染从绝对即时到需要 2-3 秒。为什么会这样?
我喜欢这个想法,但在实践中效果并不好。
std::function
是一种类类型,就像您可能编写的任何其他自定义类一样。sizeof(std::function)
因实现而异,但合理的值是字节124
。这意味着,与为每个成员函数添加0
字节相比,您将为要添加的每个成员std::function
向sizeof(Complex)
添加24
字节。与大多数机器上的sizeof(double) == 8
相比,这是很大的开销:您的Complex
类型可能是16
字节,但大约是112
字节。
此外,每个std::function
成员都必须初始化,可能需要堆分配,并且由于类型擦除,调用std::function
涉及虚函数(或等效功能)。这使得编译器很难优化,并且编译器几乎不可能内联函数,而常规成员函数由于非常简单,几乎可以保证内联。
对成员函数使用std::function
意味着您的类型无用地更大,初始化需要更多工作,并且更难优化。这就是为什么它的速度要慢得多。
1:此时,sizeof(std::function)
实际上在libstdc++,libc++和MSVC的STL上分别是32
字节,48
字节和64
字节
为了避免每个对象的开销,你可以有static constexpr
个成员(至少在 C++17 中),但你必须有一个显式的this
参数,它删除了成员函数具有的所有好处。你必须写Complex::getRe(myComplex)
而不是myComplex.getRe()
让我为您修复此代码:
struct Complex {
double re, im;
Complex() : re(0.0), im(0.0) {}
Complex(double re, double im) : re(re * 1.0), im(im * 1.0) {}
Complex(const Complex &c) = default;
~Complex() = default;
};
完全相同的结果,更好的可读性,更小的内存占用。去吧。你的代码对于恒定正确性也非常糟糕。
是的,由于多种因素,您的代码非常慢:
- 您对方法的调用现在是虚拟化的,因此它们不是内联的,您最终会因此受到严重的惩罚
- 您的对象创建/销毁现在很可能会导致动态内存分配/解除分配
- 您的对象没有变大,因此缓存未命中更多
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 在静态库中嵌入类方法
- 如何制作一个将函数作为参数的类方法
- 从父类方法返回子类对象
- 使用用户定义的参数调用future/async并调用类方法
- 重载类方法的不明确调用
- 单独定义模板化嵌套类方法的正确语法
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 如何访问由共享指针保存的类方法?
- 将子类方法声明为基类的友元
- 我的模板类方法返回错误类型?
- Qt将信号与另一个类方法连接
- 我无法使用C++指针指向类方法返回的 std::vector
- 如何在Visual Studio 2017上将类方法设置为参数并将它们与lambda一起使用?
- C++ lambda 作为类方法
- C++;类方法指针;λ;将 lambda 作为成员函数指针传递;
- 在类方法内调用lambda函数中的类方法
- 接受 lambda 作为参数的类方法 - 错误消息
- 类方法接受表示各种参数数函数的 lambda
- C++11 lambda 函数不接受类方法