C++11 std::reference_wrapper

创建一个对象或函数的引用,对象必须是 可复制(CopyConstructible)、可赋值(CopyAssignable) 的。 它经常被用作在标准容器(如 std::vector )中存储引用的机制,而标准容器通常不能保存引用。 辅助函数 std::ref 与 std::cref 常用于生成 std::reference_wrapper 对象。 std::reference_wrapper 也用于按引用传递参数给 std::bind 或 std::thread 的构造函数。 能隐式转换成 T&。 在 vector 中存储引用类型: #include <iostream>#include <list>#include <vector>#include <random>#include <functional>#include <algorithm> int main() { std::list<int> l(10); std::iota(l.begin(), l.end(), -4); // 从 -4 开始,逐个 +1 std::vector<std::reference_wrapper<int>> v(l.begin(), l.end()); // 不能在 list 上用 shuffle (要求随机访问),但能在 vector 上使用它 std::shuffle(v....

April 7, 2022 · 4 min · Rick Cui

C++11 std::ref, std::cref 与 std::bind

函数模板 ref 与 cref 是生成 std::reference_wrapper 类型对象的帮助函数,主要是与 std::bind 一起使用,默认情况下,std::bind 无法使用变量引用传递,即使原来的函数形参是引用类型的 void f(int& n1, int& n2, const int& n3) { std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; ++n1; // 增加存储于函数对象的 n1 副本 ++n2; // 增加 main() 的 n2 // ++n3; // 编译错误 error: increment of read-only reference ‘n3’ } int main() { int n1 = 1, n2 = 2, n3 = 3; // 函数对象 bound_f // 默认会将此时变量值的副本做为函数对象的参数(函数参数特例化) std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3)); n1 = 10; n2 = 11; n3 = 12; std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; bound_f(); std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; } 输出:...

April 7, 2022 · 1 min · Rick Cui

Emscripten——使用 WebIDL Binder 绑定 C++ 代码

WebIDL Binder 提供一种简单、轻量级的方法来绑定 C++ 代码。 WebIDL Binder 使用 WebIDL 定义了一种 接口语言 来把 C++ 和 JavaScript 粘合在一起。 该绑定器支持可以用 WebIDL 表达的 c++ 类型的子集。这个子集对于大多数情况来说已经足够了。 接下来,通过一个简单的例子来看一下绑定的流程,使用 WebIDL Binder 进行绑定的过程分为三个阶段: 创建一个 WebIDL 文件,用来描述 C++ 接口; 使用绑定器生成 C++ 和 JavaScript 的胶水代码; 使用 EMScripten 编译此胶水代码; 第一步:创建 WebIDL 接口文件 创建一个描述将要绑定的 C++ 类型的 WebIDL 接口文件。该文件将复制 C++ 头文件中的一些信息。比如,我们想绑定下面的 C++ 类(my_classes.h): class Foo { public: int getVal(); void setVal(int v); private: int m_val{0}; }; class Bar { public: Bar(long val); ~Bar(); void doSomething(); private: int m_val; }; IDL 接口文件就可以写成下面的形式(my_classes....

March 29, 2022 · 3 min · Rick Cui

Emscripten——C++ 调用 Js 回调函数

WASM 调用 js 代码 Emscripten 提供了两种方式,用于从 C/C++ 调用 JavaScript 的方法: 使用 emscripten_run_script() 运行脚本 编写 inline JavaScript。 最直接但稍微慢的方式是使用 emscripten_run_script()。这有效地使用 eval() 在 C/C++ 中运行指定的 JavaScript 代码。例如,调用浏览器的 alert() 函数,例如下面的代码: int EMSCRIPTEN_KEEPALIVE runScript(){ emscripten_run_script("alert('hi')"); emscripten_run_script("console.log('hello world!')"); return 0; } 从 C 中调用 JavaScript 接口的一种更快的方法是编写 inline JavaScript,使用 EM_JS() 或 EM_ASM() (以及其它相关的宏)。 EM_JS 是在 C 文件中声明一个 JavaScript 函数,使用方法参考这里。 #include <emscripten.h> EM_JS(void, myAlert, (), { alert('hello world!'); throw 'all done'; // exception }); EM_JS(void, take_args, (int x, float y), { console....

March 26, 2022 · 2 min · Rick Cui

Emscripten——js 调用 C++ 接口

Emscripten 提供了许多方法来在 JavaScript 和编译后的 C 或 c++ 之间连接和交互,我们先来看看 js 调用 WASM 的情况。 一、使用 ccall 或 cwrap callall() 调用带有指定参数的编译过的 C 函数 并返回结果,而 cwrap() 封装了编译过的 C 函数并返回一个可以正常调用的 JavaScript 函数。因此,如果计划多次调用一个编译后的函数,cwrap() 会更有用。 例如下面的 C main.cpp 文件: #include <math.h> extern "C" { int int_sqrt(int x) { return sqrt(x); } } 使用下面的命令进行编译: emcc main.cpp -o function.html -s EXPORTED_FUNCTIONS=_int_sqrt -s EXPORTED_RUNTIME_METHODS=ccall,cwrap EXPORTED_FUNCTIONS 告诉编译器哪些函数我们想要导出(不指定的函数会被删掉),EXPORTED_RUNTIME_METHODS 告诉编译器我们需要用到的运行时方法 ccall 和 cwrap,否则这些方法也会被优化掉 编译后就可以在 js 中通过 cwrap 使用了: int_sqrt = Module.cwrap('int_sqrt', 'number', ['number']) int_sqrt(12) // return 3 int_sqrt(28) // return 5 第一个参数是被 wrap 的 C 函数的名字(没有下划线),第二个参数是函数返回值在类型(如果没有返回值,使用 JavaScript 的 null 类型),第三个参数是一个参数数组(如果没有参数,可以省略)。...

March 25, 2022 · 2 min · Rick Cui