Function Object & Function Object Adapters

本文详细介绍了C++标准程序库中的Function Object及其适配器的使用方法。Function Object可以提高函数调用效率,通过将函数调用转换为内联调用。此外,文章还展示了如何使用Function Object Adapters绑定参数,简化比较操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

标准的程序库中,事先定义了一组 function object,  function object 实现了本来可以以独立函数加以定义的事物, 这样做主要是为了效率, 因为他将call变成了inline.

原来的函数是:
bool less_than(int v1, int v2)
{
 return v1<v2 ? true:false;
}

vector<int>::iterator i = sort(v.begin(), v.end(), less_than);

用function object替换后为
vector<int>::iterator i = sort(v.begin(), v.end(), less<int>() );

这两段程序都是同样的功能, 升序排列.

而Function Object Adapters 则是将比较关系中的1ST,2ND参数绑定到用户指定的类型上面去,从而使参数从一个二元参数转变成为一个一元参数

通过使用bind1st, bind2nd 方法分别可以绑定第一个或第二个参数.
如下程序:
#include<functional>
vector<int> filter( const vector<int> &vec,
 int val, less<int>& it)
{
 vector<int> nvec;
 vector<int>::const_iterator iter = vec.begin();
 
 while (( iter = find_if( iter, vec.end(), bind2nd(it, val))) != vec.end() )
 {
 nvec.push_back(*iter);
 iter++;
 }
 return nvect;

TypeError: WS is not a constructor at WebSocketStream (mqtt.min.js? [sm]:1) at createWebSocket (mqtt.min.js? [sm]:1) at Object.buildBuilderBrowser (mqtt.min.js? [sm]:1) at MqttClient.wrapper [as streamBuilder] (mqtt.min.js? [sm]:1) at MqttClient._setupStream (mqtt.min.js? [sm]:1) at new MqttClient (mqtt.min.js? [sm]:1) at Function.connect (mqtt.min.js? [sm]:1) at li.onLoad (home.js? [sm]:43) at li.&lt;anonymous&gt; (VM15444 WASubContext.js:1) at li.c.__callPageLifeTime__ (VM15444 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.11) 下述代码出现上述报错: var mqtt = require(&#39;../../utils/mqtt.min.js&#39;) const crypto = require(&#39;../../utils/crypto&#39;); Page({ data: { motionData: [ { actionType: &#39;大幅度动作&#39;, count: 19}, { actionType: &#39;小幅度动作&#39;, count: 39 }, { actionType: &#39;上半身动作&#39;, count: 15}, { actionType: &#39;下半身动作&#39;, count: 24 } ], vitalSigns: { breath: 18, // 呼吸数值 heartRate: 76 // 心率数值 }, sleepStageDescription: &#39;&#39;, // 睡眠阶段描述 currentAction: null, // 当前动作 client: null, // mqttAccountInfo: { // productKey: &quot;0ee6d6edd8&quot;, // deviceName: &quot;6876033432771f177b4c49bb_mini_app&quot;, // deviceSecret: &quot;88888888&quot;, // }, }, // sendCommand() { // this.data.client.publish(&#39;v1/M2M/#&#39;,function (err) { // if (!err) { // console.log(&#39;订阅成功!&#39;); // } // }); // 发布消息 // }, onUnload() { this.data.client.end(); // 断开连接 }, onLoad: function() { const client = mqtt.connect(&#39;wss://0ee6d6edd8.st1.iotda-app.cn-north-4.myhuaweicloud.com:8883/mqtt&#39;, { clientId: &#39;6876033432771f177b4c49bb_vibrating_sensor_0_0_2025072314&#39;, username: &#39;6876033432771f177b4c49bb_vibrating_sensor&#39;, password: &#39;115f940c0c261063d7238461e9de2ee065c1464cbff685d4eb488114425a97de&#39;, protocolVersion: 4 }); client.on(&#39;connect&#39;, () =&gt; { console.log(&#39;MQTT连接成功&#39;); client.subscribe(&#39;v1/M2M/#&#39;,function (err) { if (!err) { console.log(&#39;订阅成功!&#39;); } }); // 如果这些方法依赖于MQTT连接后的数据 this.updateSleepStageDescription(); this.updateCurrentAction(); }); client.on(&#39;message&#39;, (topic, message) =&gt; { console.log(`收到消息: ${message.toString()} 主题: ${topic}`); }); this.setData({ client }); }, updateSleepStageDescription: function () { const { motionData } = this.data; // 假设根据动作次数判断睡眠阶段 let sleepStage = &#39;&#39;; // 简单逻辑来判断睡眠阶段(可以根据动作数据的具体情况调整) if (motionData[0].count &gt; 20 &amp;&amp; motionData[1].count &gt; 20) { sleepStage = &#39;深度睡眠(动作较少)&#39;; } else if (motionData[0].count &lt; 20 &amp;&amp; motionData[1].count &lt; 20) { sleepStage = &#39;浅度睡眠(动作较多)&#39;; } else { sleepStage = &#39;浅睡眠&#39;; } // 更新睡眠阶段描述 this.setData({ sleepStageDescription: sleepStage }); }, updateCurrentAction: function () { // 模拟外部数据,动态更新当前动作 const actions = [ { name: &#39;平躺&#39;, image: &#39;../../images/lie-flat.jpg&#39; }, { name: &#39;侧翻&#39;, image: &#39;../../images/roll-over.jpg&#39; }, { name: &#39;曲腿&#39;, image: &#39;../../images/bend-leg.jpg&#39; }, { name: &#39;曲臂&#39;, image: &#39;../../images/bend-arm.jpg&#39; }, { name: &#39;转头&#39;, image: &#39;../../images/turn-head.jpg&#39; } ]; // 假设根据某种逻辑选择当前动作 const currentAction = actions[Math.floor(Math.random() * actions.length)]; this.setData({ currentAction }); }, // doConnect() { // let that = this // const options = this.initMqttOptions(); // this.data.client = mqtt.connect(&#39;wss://&#39; + this.data.mqttAccountInfo.productKey + &#39;.st1.iotda-device.cn-north-4.myhuaweicloud.com&#39;,options) // this.data.client.on(&#39;connect&#39;, function () { // console.log(&#39;连接服务器成功&#39;) // that.data.client.subscribe(&#39;/v1/M2M/#&#39;, function (err) { // if (!err) { // console.log(&#39;订阅成功!&#39;); // } // }) // }) // //接收消息监听 // that.data.client.on(&#39;message&#39;, function (topic, message) { // let msg = message.toString(); // console.log(&#39;收到消息:&#39; + msg); // that.setData({ // sensorList: JSON.parse(message) // }) // }) // }, // unconnect() { // this.data.client.end(); // this.data.client = null; // console.log(&quot;断开连接&quot;) // }, // //IoT平台mqtt连接参数初始化 // initMqttOptions() { // const params = { // productKey: this.data.mqttAccountInfo.productKey, // deviceName: this.data.mqttAccountInfo.deviceName, // deviceSecret: this.data.mqttAccountInfo.deviceSecret, // timestamp: Date.now(), // } // //生成clientId,username,password // const contentStr = &quot;clientId&quot; + params.clientId + &quot;deviceName&quot; + params.deviceName + &quot;productKey&quot; + params.productKey + &quot;timestamp&quot; + params.timestamp; // const clientId = `${params.clientId}|securemode=2,signmethod=hmacsha1,timestamp=${params.timestamp}|`; // const username = `${params.deviceName}&amp;${params.productKey}`; // //const password = &#39;dff0d64ad1bdf0651ed744d2b75b885fc1675a41d0ab26fe7ddd03722bb4db03&#39;; // const password = crypto.HmacSHA1(contentStr, params.deviceSecret).toString(); // const options = { // wsOptions: {}, // protocolVersion: 4, //MQTT连接协议版本 // clientId: clientId, // keepalive: 60, // clean: false, // username: username, // password: password, // reconnectPeriod: 1000, //1000毫秒,两次重新连接之间的间隔 // connectTimeout: 30 * 1000, //1000毫秒,两次重新连接之间的间隔 // resubscribe: true //如果连接断开并重新连接,则会再次自动订阅已订阅的主题(默认true) // } // return options; // }, // buttonChange: function (e) { // this.data.sensorList[e.currentTarget.dataset.param].value = !this.data.sensorList[e.currentTarget.dataset.param].value // console.log(this.data.sensorList) // this.data.sendData = this.data.sensorList // this.publish() // } });
07-26
&lt;think&gt;我们正在处理微信小程序中使用MQTT时出现的错误:TypeError: WS is not a constructor。 根据引用[1]中的信息,在uniapp中,他们通过条件编译分别处理H5和APP-PLUS平台,其中H5使用`ws://`,APP-PLUS使用`wx://`(注意:这里可能是笔误,因为微信小程序的协议应该是`wx://`吗?实际上,微信小程序的WebSocket协议是`wss`,但连接方式使用微信的API,而不是直接使用WebSocket对象)。 在微信小程序中,不能直接使用WebSocket对象(即浏览器中的WebSocket),而必须使用微信小程序提供的`wx.connectSocket`等API。因此,当我们尝试在小程序环境中使用原生的WebSocket(比如某些MQTT库内部使用了`new WebSocket()`)时,就会导致错误,因为小程序环境中没有WebSocket构造函数。 所以,我们需要一个能够在微信小程序中使用微信API的MQTT客户端。通常的做法是使用支持微信小程序的MQTT库,或者使用一个适配器(adapter)将微信小程序的WebSocket API转换成标准WebSocket接口。 解决方案: 1. 使用专门为微信小程序封装的MQTT库,例如`mqtt.js`配合微信小程序的适配器。 2. 在MQTT连接时,传入微信小程序的WebSocket实现作为适配器。 具体步骤: 首先,安装`mqtt`库: ``` npm install mqtt ``` 然后,在代码中引入mqtt,并指定使用微信小程序的WebSocket适配器。注意,微信小程序的WebSocket API与标准WebSocket有所不同,因此我们需要使用一个适配器来桥接。 我们可以使用`mqtt.js`的微信小程序示例: ```javascript // 引入mqtt const mqtt = require(&#39;mqtt/dist/mqtt.js&#39;); // 微信小程序适配器 const socketAdapter = require(&#39;mqtt/dist/adapters/wx.js&#39;) || mqtt.wx; // 或者,也可以直接使用mqtt.js自带的微信适配器(如果版本支持) // 在mqtt.js的4.x版本中,可以通过以下方式使用微信适配器: const client = mqtt.connect(&#39;wxs://your_broker_url&#39;, { adapter: socketAdapter // 其他选项... }); ``` 但是,请注意,微信小程序的协议是`wxs`(非标准)?实际上,微信小程序要求使用`wss`协议,但连接方式是通过微信的API。因此,在mqtt.js中,我们可以通过传入适配器来使用微信的API。 另外,微信小程序中连接WebSocket的URL必须使用`wss`协议,且域名必须在小程序后台配置。 如果上述方法不行,我们可以手动创建一个适配器。下面是一个简单的适配器示例(根据mqtt.js的文档,适配器需要实现标准WebSocket的接口): 但是,由于微信小程序的API是异步的,所以适配器需要做一些转换。幸运的是,mqtt.js已经提供了微信小程序的适配器,我们只需要引入即可。 然而,在引用[1]中,我们看到在APP-PLUS环境下使用了`wx://`协议,这可能是为了适配而自定义的。但在微信小程序中,我们应该使用`wss`协议,并且通过适配器将底层的连接方式替换为微信的API。 具体代码调整: 1. 在微信小程序中,我们使用条件编译,如`// #ifdef MP-WEIXIN`。 2. 使用微信适配器。 示例代码: ```javascript const mqtt = require(&#39;mqtt/dist/mqtt.js&#39;); let client; // #ifdef H5 // H5环境使用标准的WebSocket client = mqtt.connect(&#39;ws://broker.example.com/mqtt&#39;); // #endif // #ifdef MP-WEIXIN // 微信小程序环境 const wxAdapter = require(&#39;mqtt/dist/adapters/wx.js&#39;); client = mqtt.connect(&#39;wxs://broker.example.com/mqtt&#39;, { adapter: wxAdapter }); // #endif ``` 但是,请注意,mqtt.js的`dist/adapters/wx.js`可能不存在于某些版本中。在mqtt.js的4.1.0版本中,我们可以在源码中看到有`adapters`目录,但dist打包版本可能没有包含。因此,可能需要我们自己实现适配器。 另一种方案是使用`weapp.socket.io`或`wxmp-mqtt`这样的库,但这里我们尝试使用mqtt.js的适配器方式。 如果mqtt.js的适配器不可用,我们可以自己实现一个适配器。下面是一个简单的实现思路: ```javascript // 自定义微信小程序适配器 function WxAdapter(url, options) { this.url = url; this.options = options; this.ws = null; // 其他初始化... } WxAdapter.prototype.connect = function() { const self = this; return new Promise((resolve, reject) =&gt; { // 使用微信的connectSocket self.ws = wx.connectSocket({ url: self.url, success: () =&gt; { // 连接成功,但需要等待onOpen事件 self.ws.onOpen(() =&gt; { resolve(); }); self.ws.onError((err) =&gt; { reject(err); }); }, fail: reject }); }); }; // 还需要实现send、close等方法,以及事件监听(onmessage, onclose等) // 然后将其设置为mqtt的适配器 mqtt.connect(&#39;wxs://broker.example.com/mqtt&#39;, { adapter: WxAdapter }); ``` 但是,自己实现完整的适配器比较复杂。因此,推荐使用现成的解决方案。 实际上,mqtt.js官方仓库中有一个示例:https://github.com/mqttjs/MQTT.js/tree/master/examples/ws-example-wxapp 在这个示例中,他们使用了自定义的适配器(通过覆盖mqtt.js的WebSocket构造函数)。具体代码如下: ```javascript // 在微信小程序中,覆盖WebSocket为微信的API const socket = wx.connectSocket // 注意:wx.connectSocket返回一个SocketTask,而不是WebSocket对象 // 但是mqtt.js期望的是WebSocket实例,因此我们需要一个适配层 // 这里我们直接覆盖全局的WebSocket(在微信小程序中,全局没有WebSocket,所以我们可以自定义一个) if (typeof WebSocket === &#39;undefined&#39;) { WebSocket = function(url, protocols, options) { // 注意:微信的connectSocket返回的是一个SocketTask对象,我们需要模拟WebSocket的事件和方法 const socketTask = wx.connectSocket({ url: url, header: options &amp;&amp; options.headers, protocols: Array.isArray(protocols) ? protocols : [protocols], success: () =&gt; {}, fail: () =&gt; {} }); // 模拟WebSocket实例 const ws = { send: (data) =&gt; { socketTask.send({ data }); }, close: (code, reason) =&gt; { socketTask.close({ code, reason }); }, onopen: null, onerror: null, onmessage: null, onclose: null }; // 将SocketTask的事件转发到ws上 socketTask.onOpen((res) =&gt; { if (ws.onopen) ws.onopen(res); }); socketTask.onError((err) =&gt; { if (ws.onerror) ws.onerror(err); }); socketTask.onMessage((res) =&gt; { if (ws.onmessage) ws.onmessage({ data: res.data }); }); socketTask.onClose((res) =&gt; { if (ws.onclose) ws.onclose(res); }); return ws; }; } // 然后正常使用mqtt const client = mqtt.connect(&#39;ws://broker.example.com/mqtt&#39;); ``` 但是,这种方法需要覆盖全局的WebSocket,在微信小程序中可能可行,但要注意不要影响其他组件。 考虑到这些,我们推荐使用mqtt.js官方示例中的方式。 然而,在最新的mqtt.js(v4.2.6)中,已经内置了微信小程序的适配器。我们可以这样使用: ```javascript const mqtt = require(&#39;mqtt&#39;); const wxAdapter = require(&#39;mqtt/lib/adapters/wx.js&#39;); const client = mqtt.connect(&#39;wxs://broker.example.com&#39;, { adapter: wxAdapter }); ``` 注意:协议使用`wxs`,但实际上微信小程序要求的是`wss`,这里`wxs`可能是为了标识使用微信适配器?在连接时,mqtt.js内部会将`wxs`转换为`https`和`wss`?实际上,这个协议标识是自定义的,主要目的是让mqtt.js选择正确的适配器。在微信小程序适配器中,它会忽略协议,而使用微信的API。 因此,我们可以这样写: ```javascript const client = mqtt.connect(&#39;wxs://your_broker_url&#39;, { adapter: wxAdapter, port: 8084, // 如果使用wss,端口通常是443,但具体看你的服务器配置 // 其他选项 }); ``` 但是,请注意,微信小程序要求使用加密连接,所以必须是`wss`,因此URL也可以写成`wxs`(但实际还是wss),或者直接写`wss`,然后在适配器内部处理。 总结步骤: 1. 安装mqtt.js(最新版)。 2. 引入mqtt和微信适配器:`require(&#39;mqtt/lib/adapters/wx.js&#39;)`。 3. 连接时指定适配器。 如果以上方法仍然报错,请检查mqtt.js的版本和适配器的可用性。 另外,在微信小程序中,连接MQTT服务器时,必须确保服务器支持WebSocket,并且域名已经在小程序后台配置。 最后,由于微信小程序的环境限制,可能还需要注意: - 在小程序后台配置服务器域名(wss域名)。 - 使用真机调试,因为开发者工具中的WebSocket实现与真机不同。 如果问题仍然存在,请检查错误信息,确认错误发生在哪一行代码,然后进一步排查。 根据用户报错信息&ldquo;TypeError: WS is not a constructor&rdquo;,这个错误通常是因为在创建WebSocket实例时,传入的WS不是一个构造函数(在微信小程序中,全局没有WebSocket构造函数)。因此,通过适配器的方式可以解决。 所以,请尝试使用微信小程序适配器来连接MQTT。 如果还有问题,请提供更详细的代码和错误堆栈。&lt;/think&gt;### 解决微信小程序 MQTT 连接报错 `TypeError: WS is not a constructor` 在微信小程序中使用 MQTT 连接时出现 `TypeError: WS is not a constructor` 错误,是由于小程序环境与浏览器环境的差异导致。以下是完整的解决方案: #### 问题原因分析 1. **环境差异**:微信小程序中没有标准的 `WebSocket` 对象,必须使用微信原生 API `wx.connectSocket` 2. **协议错误**:小程序中必须使用微信专用的 `wx` 协议头 3. **适配器缺失**:MQTT.js 默认使用浏览器的 WebSocket 实现,需要适配小程序环境 #### 完整解决方案 ```javascript // 引入 MQTT 库 const mqtt = require(&#39;mqtt/dist/mqtt.js&#39;) // 微信小程序环境适配器 function wxAdapter(url, options) { return { connect: function(callback) { const socketTask = wx.connectSocket({ url: url.replace(/^wx:\/\//, &#39;wss://&#39;), // 转换协议 header: options.headers, protocols: options.protocols || [], success: () =&gt; callback(null, socketTask), fail: err =&gt; callback(err) }) }, // 其他必要方法实现... } } // 创建 MQTT 客户端 let client = null // 微信小程序环境 // #ifdef MP-WEIXIN const options = { port: 8083, connectTimeout: 4000, clientId: &quot;mqtt_&quot; + Math.random().toString(16).substr(2, 8), // 使用微信适配器 adapter: wxAdapter } // 注意:必须使用 wx:// 协议头 client = mqtt.connect(&quot;wx://your-server-domain.com/mqtt&quot;, options) // #endif // 事件监听 client.on(&#39;connect&#39;, () =&gt; { console.log(&#39;MQTT 连接成功&#39;) wx.onSocketMessage(res =&gt; { console.log(&#39;收到消息:&#39;, res.data) }) }) client.on(&#39;error&#39;, err =&gt; { console.error(&#39;MQTT 连接错误:&#39;, err) wx.showToast({ title: &#39;连接失败&#39;, icon: &#39;none&#39; }) }) ``` #### 关键配置说明 1. **协议转换**: ```javascript url: url.replace(/^wx:\/\//, &#39;wss://&#39;) // 内部将 wx:// 转为 wss:// ``` 小程序实际使用 `wss` 协议,但 MQTT 连接时需使用 `wx://` 前缀触发适配器 2. **微信适配器**: ```javascript adapter: wxAdapter // 强制使用自定义的微信适配器 ``` 这是解决 `WS is not a constructor` 的核心,替换了默认的 WebSocket 实现 3. **域名配置**: - 在小程序后台配置合法的 **wss 域名** - 开发阶段可在开发者工具中勾选「不校验合法域名」 #### 常见问题排查 1. **真机调试失败**: ```javascript // 真机必须使用 wss 且配置合法域名 wx.connectSocket({ url: &#39;wss://your-domain.com/mqtt&#39;, success() { console.log(&#39;连接建立&#39;) } }) ``` 2. **自动重连机制**: ```javascript // 连接断开时自动重连 wx.onSocketClose(() =&gt; { setTimeout(() =&gt; { client.reconnect() }, 3000) // 3秒后重连 }) ``` 3. **多页面共享连接**: ```javascript // app.js 中全局管理连接 App({ globalData: { mqttClient: null }, onLaunch() { this.globalData.mqttClient = mqtt.connect(&quot;wx://...&quot;, options) } }) ``` #### 注意事项 1. 小程序 **单设备最多支持 5 个 WebSocket 连接**,超出会报错 2. 后台运行时连接可能被断开,需监听 `onHide`/`onShow` 事件管理连接状态 3. iOS 设备需确保服务器 TLS 证书有效,避免 `SSL handshake failed` 错误 &gt; 官方参考:[微信小程序 WebSocket 文档](https://developers.weixin.qq.com/miniprogram/dev/api/network/websocket/wx.connectSocket.html)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值