C_and_CPP 板


LINE

※ 引述《IOP14759 (iop14759)》之铭言: : 开发平台(Platform): (Ex: Win10, Linux, ...) : WIN8 : 编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出) : c++builder : 额外使用到的函数库(Library Used): (Ex: OpenGL, ...) : 无 : 问题(Question): : 想请教此程式如果想写成回圈该怎麽写? : 程式码(Code):(请善用置底文网页, 记得排版,禁止使用图档) : int pcs,ID,count; : AnsiString bit0,bit1,bit2,bit3,bit4,bit5,bit6,bit7,ID_display; : //将ID转为2进制的字串 : bit1=(ID&0x02)>>1; : bit2=(ID&0x04)>>2; : bit3=(ID&0x08)>>3; : bit4=(ID&0x10)>>4; : bit5=(ID&0x20)>>5; : bit6=(ID&0x40)>>6; : bit7=(ID&0x80)>>7; : ////////////////////////////////////////////////////////////////// : if(pcs==1)ID_display=bit7; : if(pcs==2)ID_display=bit7+bit6; : if(pcs==3)ID_display=bit7+bit6+bit5; : if(pcs==4)ID_display=bit7+bit6+bit5+bit4; : if(pcs==5)ID_display=bit7+bit6+bit5+bit4+bit3; : if(pcs==6)ID_display=bit7+bit6+bit5+bit4+bit3+bit2; : if(pcs==7)ID_display=bit7+bit6+bit5+bit4+bit3+bit2+bit1; //最多7个 : ///////////////////////////////////////////////////////////////// : if(count==3){Form1->Label31->Caption=ID_display;} //第三栏id : if(count==2){Form1->Label19->Caption=ID_display;} //第二栏 id : if(count==1){Form1->Label1->Caption=ID_display;} //第一栏id : ////////////////////////////////////////////////////////////////// : 补充说明(Supplement): : 这是小弟的最近写的,每次读1~7个ID,每个ID随机为1或0 : 我是用字串+字串的方式来显示每个ID分别是1或0 : 因为暂时没有需要太多次回圈所以用笨方法一个个判断 : 但是自己知道这方法很笨,如果以後要读更多ID我就无解了 好读(?)网页(?)版:https://pastebin.com/raw/6CGgV6Cx - 因为不知道 AnsiString 是什麽,这里我先使用 std::string 代替,还请见谅 - 示范部分,单纯为了方面看到内容,存入了 1 跟 0 以外的数值,一切以原 PO 的规格为主 id 顺序的部分啊,我就使用递增去作了 首先,我们来看看这段逻辑 if(pcs==1)ID_display=bit7; if(pcs==2)ID_display=bit7+bit6; if(pcs==3)ID_display=bit7+bit6+bit5; if(pcs==4)ID_display=bit7+bit6+bit5+bit4; if(pcs==5)ID_display=bit7+bit6+bit5+bit4+bit3; if(pcs==6)ID_display=bit7+bit6+bit5+bit4+bit3+bit2; if(pcs==7)ID_display=bit7+bit6+bit5+bit4+bit3+bit2+bit1; //最多7个 让我们先把他变成一个函数 std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1, std::string bit2, std::string bit3, std::string bit4, std::string bit5, std::string bit6, std::string bit7) { if (pcs == 1) return bit7; if (pcs == 2) return bit7 + bit6; if (pcs == 3) return bit7 + bit6 + bit5; if (pcs == 4) return bit7 + bit6 + bit5 + bit4; if (pcs == 5) return bit7 + bit6 + bit5 + bit4 + bit3; if (pcs == 6) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2; if (pcs == 7) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1; } 可以观察到,事情似乎有些有趣。来改写一下 std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1, std::string bit2, std::string bit3, std::string bit4, std::string bit5, std::string bit6, std::string bit7) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7); // TODO pcs 小於等於 0 该做些什麽? if (pcs == 1) return bit7; if (pcs == 2) return rec(1) + bit6; if (pcs == 3) return rec(2) + bit5; if (pcs == 4) return rec(3) + bit4; if (pcs == 5) return rec(4) + bit3; if (pcs == 6) return rec(5) + bit2; if (pcs == 7) return rec(6) + bit1; // TODO pcs 大於 7 该做些什麽? } 由於是递回结构,我们观察前面两个看看 // 当 pcs 为 1 时,我们取尾巴 1 个 if (pcs == 1) return bit7; // 当 pcs 为 2 时,我们取尾巴 2 个 if (pcs == 2) return rec(1) + bit6; 因此我们可以 "合理" 推断,当 pcs 为 n 时,我们取尾巴 n 个,这样就完成刚刚的 TODO 了 (当然,合理因人而异,这里只是提供一种可能性而已,毕竟原 PO 并没有提供其他的线索) std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1, std::string bit2, std::string bit3, std::string bit4, std::string bit5, std::string bit6, std::string bit7) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7); if (pcs <= 0) return ""; if (pcs == 1) return rec(0) + bit7; if (pcs == 2) return rec(1) + bit6; if (pcs == 3) return rec(2) + bit5; if (pcs == 4) return rec(3) + bit4; if (pcs == 5) return rec(4) + bit3; if (pcs == 6) return rec(5) + bit2; if (pcs == 7) return rec(6) + bit1; if (pcs == 8) return rec(7) + bit0; return rec(8); } Ok,现在我们来处理应该要是 ID 但是名字却是 bit 的变数们,让我们稍微改变一下写法 std::string unkonwn_logic_a(int pcs, std::string ids) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, ids); if (pcs <= 0) return ""; if (pcs == 1) return rec(0) + ids.at(7); if (pcs == 2) return rec(1) + ids.at(6); if (pcs == 3) return rec(2) + ids.at(5); if (pcs == 4) return rec(3) + ids.at(4); if (pcs == 5) return rec(4) + ids.at(3); if (pcs == 6) return rec(5) + ids.at(2); if (pcs == 7) return rec(6) + ids.at(1); if (pcs == 8) return rec(7) + ids.at(0); return rec(8); } 这个时候,我们会发现几个有趣的数字,0 以及 8。他们用在了递回的参数,以及 ids 的 index 使用。 我们可以很快的观察到 8 这个数字其实就是 ids 的长度,让我们基於这个观察再修改一下 std::string unkonwn_logic_a(int pcs, std::string ids) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, ids); const auto &ids_len = ids.length(); if (pcs <= 0) return ""; if (pcs == 1) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 2) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 3) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 4) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 5) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 6) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 7) return rec(pcs - 1) + ids.at(ids_len - pcs); if (pcs == 8) return rec(pcs - 1) + ids.at(ids_len - pcs); return rec(8); } 哎呀,似乎发现了不得了的事情呢。这次,让我们摆脱 8 的诅咒,使用 ids 的长度来处理他 std::string unkonwn_logic_a(int pcs, std::string ids) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, ids); const auto &ids_len = ids.length(); if (pcs <= 0) return ""; if (pcs > ids_len) return rec(ids_len); return rec(pcs - 1) + ids.at(ids_len - pcs); } 递回... 递回... 递... 回... fold... 由於字串的相加具有结合律,(sa + sb) + sc = sa + (sb + sc),我们可以将原本的 right fold 改以 left fold 实作,刚好 std::accumulate 就是 left fold // 这个是小帮手. std::vector<int> range(int from, int to) { std::vector<int> ret{}; for (int i = from; i <= to; i++) { ret.emplace_back(i); } return ret; } std::string unkonwn_logic_a(int pcs, std::string ids) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, ids); const auto &ids_len = ids.length(); if (pcs <= 0) return ""; if (pcs > ids_len) return rec(ids_len); const auto &pcs_range = range(1, pcs); return std::accumulate(pcs_range.cbegin(), pcs_range.cend(), std::string{}, [&](std::string acc, int cur_pcs) { acc += ids.at(ids_len - cur_pcs); return std::move(acc); }); } 最後,我们可以使用 for loop 去表达 left fold。不知道大家的 for loop 除了 left fold,还 用来表达了那些概念呢? 感觉会不小心搞不清楚是在 for 什麽呢 std::string unkonwn_logic_a(int pcs, std::string ids) { using namespace std::placeholders; const auto &rec = std::bind(unkonwn_logic_a, _1, ids); const auto &ids_len = ids.length(); if (pcs <= 0) return ""; if (pcs > ids_len) return rec(ids_len); auto acc = std::string{}; for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) { acc += ids.at(ids_len - cur_pcs); } return acc; } 可以针对 for loop 的特性做一些微调,让程式码更简洁,以及修改一下型别,让程式更明确 std::string unkonwn_logic_a(size_t pcs, std::string ids) { const auto &ids_len = ids.length(); pcs = std::min(pcs, ids_len); auto acc = std::string{}; for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) { acc += ids.at(ids_len - cur_pcs); } return acc; } 好了,现在可以回答原 PO 的问题:想请教此程式如果想写成回圈该怎麽写? 嗯,大概就是这样 诶,等等,你说那些 bit operation 怎麽不见了,好吧,那让我们处理处理。 首先,我们修改一下 unkonwn_logic_a 取得长度跟取 index 的形式,新增几个小帮手 std::string::size_type length(const std::string &s) { return s.length(); } std::string::value_type at(const std::string::size_type pos, const std::string &s) { return s.at(pos); } namespace std { std::string to_string(const std::string::value_type c) { return {c}; } } // namespace std std::string unkonwn_logic_a(size_t pcs, std::string ids) { const auto &ids_len = length(ids); pcs = std::min(pcs, ids_len); auto acc = std::string{}; for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) { acc += std::to_string(at(ids_len - cur_pcs, ids)); } return acc; } 接着把 unkonwn_logic_a 改为 template 的形式 (小秘密,函数实作根本一样)。 这里比较麻烦的是决定 pcs 的型别,详细可以查查 decltype 跟 declval 的用法,这里不赘述。 template <typename IDS> std::string unkonwn_logic_a(decltype(length(std::declval<IDS>())) pcs, IDS &&ids) { const auto &ids_len = length(ids); pcs = std::min(pcs, ids_len); auto acc = std::string{}; for (decltype(pcs) cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) { acc += std::to_string(at(ids_len - cur_pcs, ids)); } return acc; } 那假设我们想要用 uint8_t 去存 ids,就帮 uint8_t 实作 length, at 跟 std::to_string 就好了 size_t length(const uint8_t &b) { return sizeof(b) * 8; } uint8_t at(const size_t pos, const uint8_t &b) { return (b & (1 << pos)) ? 1 : 0; } namespace std { std::string to_string(const uint8_t b) { return std::to_string((unsigned){b}); } } // namespace std 完成後,下面的程式码就都可以运作了,在浏览器上跑跑看吧 https://godbolt.org/z/wrd7Rv 这样就优雅解决原 PO 的烦恼了:如果以後要读更多ID我就无解了 对於通用的需求,我们可以使用 template 版本的 unkonwn_logic_a,只要帮存 id 的结构实作 length, at 跟 std::to_string 就可以。而对於不喜欢 template 版本的人,也可以重新写一份专 属於特定型别的 unkonwn_logic_a,没问题的。 最後一段那个 count 跟 label 的我实在看不懂,请让我无视他。 --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 111.185.85.36 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1585685214.A.57D.html
1F:推 s4300026: 推荐这篇文章。 04/01 08:26
2F:推 LPH66: 推一个 04/01 08:46
3F:推 cuteSquirrel: 好强 04/01 19:59
4F:推 NciscalA: 推。 04/02 11:33
5F:→ loveme00835: xD 好多洞恐怖 04/02 20:28
6F:推 loveme00835: 在做 lifetime extension 的时候确保你的函式是什麽 04/04 01:35
7F:→ loveme00835: 行为会比较好喔,而且看来没有好好利用 ADL 而选择 04/04 01:35
8F:→ loveme00835: 把东西直接丢进 std 命名空间这污染不一般,decltyp 04/04 01:35
9F:→ loveme00835: e() 虽然说很方便,但你还是没有避掉隐式转型,所以 04/04 01:35
10F:→ loveme00835: 大部分用 auto/decltype 的情境都很多余 04/04 01:35
11F:→ loveme00835: 通常我们在模板化的时候会尽量使用 STL 常见的介面 04/04 01:45
12F:→ loveme00835: ,所以呼叫std::string::size() 会是比较好的选项, 04/04 01:45
13F:→ loveme00835: 如此未来要换成 std::string_view / std::span 都是 04/04 01:45
14F:→ loveme00835: 可行的选项,不然这个模板就是割鸡用牛刀的范例,pr 04/04 01:45
15F:→ loveme00835: iority 因此降低了。另外应该是为了避掉编译错误才 04/04 01:45
16F:→ loveme00835: 把参数宣告成 ref to const uint8_t 还有 const uin 04/04 01:45
17F:→ loveme00835: t8_t 吧?整份扣看起来很糟糕 04/04 01:45
18F:推 sarafciel: 推 04/06 01:03







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:e-shopping站内搜寻

TOP