blueloveTH 2 jaren geleden
bovenliggende
commit
5bbb534b20
1 gewijzigde bestanden met toevoegingen van 59 en 0 verwijderingen
  1. 59 0
      docs/bindings.md

+ 59 - 0
docs/bindings.md

@@ -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.