基于C可变参数模板格式化字符串

遨游于C++世界时,最讨厌的当属于对c-style的兼容????。 在格式化字符串时,通常使用的是snprintf这个c函数。snprintf是sprintf的安全版,能够避免缓冲区溢出。 char buf[1024] = {0};std::string s = "Hello world";snprintf(buf, sizeof(buf), "format str: %s", s.c_str());snprintf接受的参数跟printf差不多,都是c-style的数据类型,如%s接受的是const char*类型的数据,这就需要我们将std::string做一个转换。这一个小小的转换让我觉得非常不爽,有没有可能让std::string在做某个函数的参数时能自动做转换?甚至让一个将一个普通的对象自动转换成const char*类型? 接下来我们将利用c++11的可变参数模板(variadic templates)、参数包(parameters pack)、完美转发(perfect forwarding)等特性来实现这一想法。 参数列表完美转发写C++代码时,我满脑子都是怎么最大限度地提高性能。我们这次的目标也一样,在提供方便的同时,不要对性能有太大影响,甚至不影响。 首先是要将传入fmt函数的参数完美转发至snprintf。 template<typename... Args>string fmt(const char *format, Args&&... args) { char buf[128] = {0}; snprintf(buf, sizeof(buf), format, convert(std::forward<Args>(args))...); return buf;}这是一个可变参数模板,args表示传入的参数们。我们的思路是将传入的参数做一个转换之后传给snprintf。 为了原封不动的保持左右值引用,首先是用Args&&代替Args的参数类型,此处模板函数的Args需要编译器推导,所以是一个通用引用(Universal reference),可以指代左值或右值。用std::forward<Args>能保持参数的左右值性质,做到参数的完美转发。 自动参数转换在convert这个函数中,我们要将特定的类型转换成const char*类型,而那些能被snprintf接受的类型如int, double, char*,则原封不动的返回。 convert函数针对不同的参数类型需要返回不同的类型。这里也将返回值作为一个模板类型即可。 template<typename T>struct item_return { using type = T&&;};convert函数的定义为: template<typename T>inline typename item_return<T>::type convert(T&& arg) { return static_cast<T&&>(arg);}convert函数默认将传入的参数原封不动的返回。接下来我们要做模板的偏特化,对于指定的对象,将其转换为const char *类型 ...

May 30, 2019 · 1 min · jiezi

Vue框架TypeScript装饰器使用指南

关键词 装饰器 Decorator 元编程前言装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。本篇先从项目的宏观角度来总结一下Decorator如何组织。我会持续分享一些知识整理,如果文章对您有帮助记得点赞鼓励一下哦????~,也可以通过邮件方式联系我文章列表: https://juejin.im/user/5bc8b9… 邮箱地址: 595506910@qq.com目录主要的Decorator依赖vue-class-componentvuex-classvue-property-decoratorcore-decorators自定义Decorator示例哪些功能适合用Decorator实现Decorator实现小TipsSee also主要的Decorator依赖vue-cli3 默认支持Decorator, 年初重写了一个design库主要依赖官方和社区提供的Decorator来实现的组件。Decorator可以非侵入的装饰类、方法、属性,解耦业务逻辑和辅助功能逻辑。以下是主要的三方Decorator组件,有了这些组件常用的Vue特性就可以全部转成Decorator风格了。vue-class-component@Component 如果您在声明组件时更喜欢基于类的 API,则可以使用官方维护的 vue-class-component 装饰器实时计算computed属性, get computedMsg () {return ‘computed ’ + this.msg}生命周期钩子 mounted () {this.greet()}vuex-class让Vuex和Vue之间的绑定更清晰和可拓展@State@Getter@Action@Mutationvue-property-decorator这个组件完全依赖于vue-class-component.它具备以下几个属性:@Component (完全继承于vue-class-component)@Prop:父子组件之间值的传递@Emit:子组件向父组件传递@Model:双向绑定@Watch:观察的表达式变动@Provice:在组件嵌套层级过深时。父组件不便于向子组件传递数据。就把数据通过Provide传递下去。@Inject:然后子组件通过Inject来获取Mixins (在vue-class-component中定义);建议项目中只引用vue-property-decorator就可以了,避免@Component从vue-class-component和vue-property-decorator两个中随意引用。core-decorators@readonly@autobind : TSX 回调函数中的 this,类的方法默认是不会绑定 this 的,可以使用autobind装饰器@override总结一下主要就分成这三类:修饰类的:@Component、@autobind;修饰方法的:@Emit、@Watch、@readonly、@override;修饰属性的:@Prop、@readonly;以上引用方法等详系内容可查看官方文档。要想完整的发挥Decorator的价值就需要根据需要自定义一些装饰器。下面自定义部分就来实现一个记录日志功能的装饰器。自定义Decorator示例@Logger,1.Logger日志装饰器通常是修饰方法,Decorater则是在运行时就被触发了,日志记录是在方法被调用时触发,示例中通过自动发布事件实现调用时触发。2.为增加日志记录的灵活性,需要通过暴露钩子函数的方式来改变日志记录的内容。期望的日志格式{ “logId”:"", // 事件Id “input”:"", // 方法输入的内容 “output”:"", // 方法输出的内容 “custom”:"" // 自定义的日志内容}实现export function Logger(logId?: string, hander?: Function) { const loggerInfo =Object.seal({logId:logId, input:’’,output:’’, custom: ‘’}); const channelName = ‘__logger’; const msgChannel = postal.channel(channelName); msgChannel.subscribe(logId, logData => { // 根据业务逻辑来处理日志 console.log(logData); }); return function (target: any, key: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> { const oldValue = descriptor.value descriptor.value = function () { const args: Array<any> = []; for (let index in arguments) { args.push(arguments[index]); } loggerInfo.input = ${key}(${args.join(',')}); // 执行原方法 const value = oldValue.apply(this, arguments); loggerInfo.output = value; hander && (loggerInfo.custom = hander(loggerInfo.input, loggerInfo.output) || ‘’); // 被调用时,会自动发出一个事件 msgChannel.publish(logId, loggerInfo); } return descriptor }}使用// 直接使用非常简洁@Logger(’event_get_detial1’)getDetial(id?: string, category?: string) { return “详细内容”;}// 或者使用自定义,让日志和业务逻辑分离@Logger(’event_get_detial2’, (input, output) => { return ‘我是自定义内容’;})getDetial2(id?: string, category?: string) { return “详细内容”;}…<button @click=“getDetial2(‘1000’, ‘a’)">获取详情</button>效果: {logId: “event_get_detial2”, input: “getDetial2(1000,a)”, output: “详细内容”, custom: “我是自定义内容”}, 每次点击按钮都会触发一次。TODO: 这里还需要对输入参数和输出参数中的引用数据类型做处理。同时还需要掌握:装饰器工厂、装饰器组合、装饰器求值、参数装饰器、元数据哪些功能适合用Decorator实现官网和社区提供的这些Decorator, 可以作为自己框架的底层设计。日志功能全局都得用,调用方法基本一致,是最适合使用装饰器来实现,并且每个项目的日志记录各有差异,最适合自定义这部分。Decorator实现小Tips考虑下各类Decorator叠加和共存的问题,可以参考官网关于装饰器组合描述Decorator 的目标是在原有功能基础上,添加功能,切忌覆盖原有功能类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的类)装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。类是不会提升的,所以就没有这方面的问题。注意迁移速度、避免一口吃成胖子的做法不要另起炉灶对主流库创建Decorator库,主流库维护成本很高还是得有官方来维护,为保证质量不使用个人编写的Decorator库。自己在创建Decorator库时也要有这个意识,仅做一些有必要自定义的。Decorator 不是管道模式,decorator之间不存在交互,所以必须注意保持decorator独立性、透明性Decorator 更适用于非业务功能需求确定 decorator 的用途后,切记执行判断参数类型decorator 针对每个装饰目标,仅执行一次See alsots官网装饰器说明【深入阅读】 https://www.tslang.cn/docs/ha...Decorator作用在不同的声明类型target、key说明 https://segmentfault.com/a/11...JS 装饰器(Decorator)场景实战 https://zhuanlan.zhihu.com/p/...Decorators in ES7 https://zhuanlan.zhihu.com/p/...vue组件 风格指南 https://cn.vuejs.org/v2/style…使用Typescript封装一款装饰器风格的Web框架 https://zhuanlan.zhihu.com/p/...Axios 装饰器实现 1.https://github.com/glangzh/re… 2.https://www.npmjs.com/package…声明计算属性用的。 https://my.oschina.net/lpcysz...autobind https://blog.csdn.net/liubigg...vue-class-component源码阅读 https://www.jianshu.com/p/cfe…函数和方法的区别 https://www.imooc.com/article…很多人整理过使用方法 https://www.cnblogs.com/navys…举个例子 join(separator?: string): string;vue源码解析系列-compute实现机制 https://segmentfault.com/a/11… ...

February 20, 2019 · 1 min · jiezi