WebAssembly初级——Embind普通函数、C++类(四)

系列文章目录

WebAssebmly初级


前言

如果之前看过前几篇文章,在了解了什么是WebAssebmly、WebAssebmly和C++,并且搭建好了WebAssebmly环境,自己也尝试过使用WebAssebmly调用C++方法,那么很容易就发现由于WebAssebmly只识别C风格的接口,并且在调试的时候明显函数名是C风格的(前面要加_),例如:
在这里插入图片描述
而本文主要介绍如何使用EMSCRIPTEN_BINDINGS()为函数、类、值类型、指针(包括原始指针和智能指针)、枚举和常量创建绑定,以及如何为可以在 JavaScript 中覆盖的抽象类创建绑定。

|版本声明:山河君,未经博主允许,禁止转载!

一、Embind

1.作用

Embind用于将 C++ 函数和类绑定到 JavaScript,以便编译后的代码可以被“正常”的 JavaScript 以自然的方式使用。Embind还支持从 C++ 调用 JavaScript 类。

Embind 支持绑定大多数 C++ 结构,包括 C++11 和 C++14 中引入的结构。它唯一重要的限制是它目前不支持具有复杂生命周期语义的原始指针。

2.使用介绍

  1. 所有通过Embind暴露的symblols都可以在Module对象获取
  2. 只绑定那些实际需要的项目,因为每次绑定都会增加代码大小
  3. JavaScript,特别是 ECMA-262 版本 5.1,不支持终结器 或带有回调的弱引用。因此,Emscripten 无法自动调用 C++ 对象上的析构函数。
  4. JavaScript 代码必须明确删除它收到的任何 C++ 对象句柄,否则 Emscripten 堆将无限增长。

3.使用步骤

  1. 添加头文件#include <emscripten/bind.h>
  2. 使用EMSCRIPTEN_BINDINGS()进行绑定,将关键方法进行映射,
  3. 编译时加入--bind参数

二、绑定普通函数和类

1.不使用EMSCRIPTEN_BINDINGS()

在之前初步的使用WebAssebmly时,通常使用如下:

将方法强制为C接口,并加上宏EMSCRIPTEN_KEEPALIVE表明此方法需一直保留不被优化

#ifdef __cplusplus
extern "C" {
#endif

void EMSCRIPTEN_KEEPALIVE myFunction(void) {
  printf("我的函数已被调用\n");
}

#ifdef __cplusplus
}
#endif

在调用的时候,方法前必须要加上’_’
在这里插入图片描述

2.绑定普通函数

接下来看一个简单的例子

#include <emscripten/emscripten.h>
#include <emscripten/bind.h>

using namespace emscripten;

float compareBig(int a, int b) {
        return a > b ? a : b;
    }

EMSCRIPTEN_BINDINGS(my_module) {
    function("compareBig", &compareBig);
}

使用命令

emcc --bind -o quick_example.js quick_example.cpp

此时,就可以用Module进行直接调用
在这里插入图片描述

3.绑定类

class MyClass {
public:
  MyClass(int num){ m_num = num; };

  void CompareBig(int x, int y)
  {
	  printf("Big one is %d\n", x > y ? x : y);
  }

  static int getNum(const MyClass& instance) {
    return instance.printfNum;
  }

private:
  int printfNum()
  {
	  return m_num;
  }

private:
	int m_num;
};

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
  class_<MyClass>("MyClass")
    .constructor<int>() //构造函数
    .function("CompareBig", &MyClass::CompareBig) //普通类成员函数
    .class_function("getNum", &MyClass::getNum) //静态类成员函数
    ;
}

使用后记得需要释放:instance.delete()
在这里插入图片描述

4.绑定属性

假如上个例子里面打算直接给m_num赋值,而它本身又是一个私有变量,我们可以直接设置属性将其暴露

class MyClass {
public:
  MyClass(int num){ m_num = num; };

  void CompareBig(int x, int y)
  {
	  printf("Big one is %d\n", x > y ? x : y);
  }

  static int getNum(MyClass& instance) {
    return instance.printfNum();
  }

	int getNumValue() const
	{
		printf("getNumvalue:%d\n", m_num);
		return m_num;
	}

	void setNum(int num)
	{
		printf("setNum:%d\n", num);
		m_num = num;
	}

private:
  int printfNum()
  {
	  return m_num;
  }

private:
	int m_num;
};

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
  class_<MyClass>("MyClass")
    .constructor<int>() //构造函数
    .function("CompareBig", &MyClass::CompareBig) //普通类成员函数
	.property("m_num", &MyClass::getNumValue, &MyClass::setNum)
    .class_function("getNum", &MyClass::getNum) //静态类成员函数
    ;
}

在这里插入图片描述

三、绑定

感知机是二分的线性分模型,其输入为实例的特征向量,输出为实例的别,取 +1 和 -1 二值。感知机对应于输入空间(特征空间)中将实例划分为正负两的分离超平面,属于判别模型。 感知机学习算法是基于随机梯度下降法的。具体地,首先任意选取一个超平面,然后用梯度下降法不断地极小化目标函数,找出最优超平面。 以下是感知机算法的C++实现及案例代码: ```c++ #include <iostream> #include <vector> #include <random> using namespace std; class Perceptron { public: Perceptron(int feature_num) : w(feature_num), b(0) {} void train(const vector<vector<double>>& X, const vector<double>& y, int max_iter = 100) { int n_samples = X.size(); int n_features = X[0].size(); mt19937 rng(0); uniform_int_distribution<int> dist(0, n_samples - 1); for (int iter = 0; iter < max_iter; iter++) { int i = dist(rng); double wx = 0; for (int j = 0; j < n_features; j++) { wx += X[i][j] * w[j]; } double yi = y[i]; if (yi * (wx + b) <= 0) { for (int j = 0; j < n_features; j++) { w[j] += yi * X[i][j]; } b += yi; } } } double predict(const vector<double>& x) { double wx = 0; int n_features = x.size(); for (int i = 0; i < n_features; i++) { wx += x[i] * w[i]; } return wx + b > 0 ? 1 : -1; } void print_weights() const { cout << "w = ["; for (double wi : w) { cout << wi << ", "; } cout << "], b = " << b << endl; } private: vector<double> w; double b; }; int main() { vector<vector<double>> X{ {3, 3}, {4, 3}, {1, 1} }; vector<double> y{1, 1, -1}; Perceptron model(X[0].size()); model.train(X, y); model.print_weights(); cout << "predict([3, 4]) = " << model.predict({3, 4}) << endl; return 0; } ``` 在上述代码中,Perceptron代表感知机模型。train函数接受训练数据X和y,以及最大迭代次数max_iter,默认为100。predict函数接受一个样本特征向量x,返回其预测的别标签。print_weights函数打印训练后得到的权重和偏置项。 本例中,使用学习率为1的随机梯度下降法进行模型训练。训练数据X是一个3x2的矩阵,y是一个包含3个元素的向量,表示3个样本的别标签。模型训练完毕后,使用predict函数对特定样本进行预测。 以上是感知机算法的C++实现及案例代码,希望对你有所帮助。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值