This commit is contained in:
blueloveTH 2023-10-08 16:08:29 +08:00
parent 3478ddeeb0
commit 5bbb534b20

View File

@ -49,6 +49,65 @@ vm->bind(obj,
});
```
#### How to capture something
By default, the lambda being bound is a C function pointer,
you cannot capture anything! The following example does not compile.
```cpp
int x = 1;
vm->bind(obj, "f() -> int", [x](VM* vm, ArgsView args){
// error: cannot capture 'x'
return py_var(vm, x);
});
```
I do not encourage you to capture something in a lambda being bound
because:
1. Captured lambda runs slower and causes "code-bloat".
2. Captured values are unsafe, especially for `PyObject*` as they could leak by accident.
However, there are 3 ways to capture something when you really need to.
The most safe and elegant way is to subclass `VM` and add a member variable.
```cpp
class YourVM : public VM{
public:
int x;
YourVM() : VM() {}
};
int main(){
YourVM* vm = new YourVM();
vm->x = 1;
vm->bind(obj, "f() -> int", [](VM* _vm, ArgsView args){
// do a static_cast and you can get any extra members of YourVM
YourVM* vm = static_cast<YourVM*>(_vm);
return py_var(vm, vm->x);
});
return 0;
}
```
The 2nd way is to use `vm->bind`'s last parameter `userdata`, you can store a POD type smaller than 8 bytes.
And use `lambda_get_userdata<T>(args.begin())` to get it inside the lambda body.
```cpp
int x = 1;
vm->bind(obj, "f() -> int", [](VM* vm, ArgsView args){
// get the userdata
int x = lambda_get_userdata<int>(args.begin());
return py_var(vm, x);
}, x); // capture x
```
The 3rd way is to change the macro `PK_ENABLE_STD_FUNCTION` in `config.h`:
```cpp
#define PK_ENABLE_STD_FUNCTION 0 // => 1
```
Then you can use standard capture list in lambda.
### Bind a struct
Assume you have a struct `Point` declared as follows.