c++实现字符串"装饰器"

395 阅读3分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。

众所周知,c++中@符号一直是一个迷,因为这个符号似乎什么用都没有,于是……
c++可以利用模板,不过里面只能这么写template<char... T> 看上去似乎不能放const char*,但就是要放呢,能不能把const char*展开呢,答案是yes!

那么我们可以利用宏,默认其连接一个32位宽度的且全部都是'\0'的字符串,其作用是充当占位符。【32位宽的'\0'占位符,可以提供33位的有效长度,因为空字符串占1字节】

#include <iostream>
#define STR_1(k,i)  k[i]
#define STR_2(k,i)  k[i], STR_1(k,i+1)
#define STR_3(k,i)  k[i], STR_2(k,i+1)
#define STR_4(k,i)  k[i], STR_3(k,i+1)
#define STR_5(k,i)  k[i], STR_4(k,i+1)
#define STR_6(k,i)  k[i], STR_5(k,i+1)
#define STR_7(k,i)  k[i], STR_6(k,i+1)
#define STR_8(k,i)  k[i], STR_7(k,i+1)
#define STR_9(k,i)  k[i], STR_8(k,i+1)
#define STR_10(k,i) k[i], STR_9(k,i+1)
#define STR_11(k,i) k[i], STR_10(k,i+1)
#define STR_12(k,i) k[i], STR_11(k,i+1)
#define STR_13(k,i) k[i], STR_12(k,i+1)
#define STR_14(k,i) k[i], STR_13(k,i+1)
#define STR_15(k,i) k[i], STR_14(k,i+1)
#define STR_16(k,i) k[i], STR_15(k,i+1)
#define STR_17(k,i) k[i], STR_16(k,i+1)
#define STR_18(k,i) k[i], STR_17(k,i+1)
#define STR_19(k,i) k[i], STR_18(k,i+1)
#define STR_20(k,i) k[i], STR_19(k,i+1)
#define STR_21(k,i) k[i], STR_20(k,i+1)
#define STR_22(k,i) k[i], STR_21(k,i+1)
#define STR_23(k,i) k[i], STR_22(k,i+1)
#define STR_24(k,i) k[i], STR_23(k,i+1)
#define STR_25(k,i) k[i], STR_24(k,i+1)
#define STR_26(k,i) k[i], STR_25(k,i+1)
#define STR_27(k,i) k[i], STR_26(k,i+1)
#define STR_28(k,i) k[i], STR_27(k,i+1)
#define STR_29(k,i) k[i], STR_28(k,i+1)
#define STR_30(k,i) k[i], STR_29(k,i+1)
#define STR_31(k,i) k[i], STR_30(k,i+1)
#define STR_32(k,i) k[i], STR_31(k,i+1)
#define R(N) STR_32(N"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",0)
//目前可以支持32位字符串的长度,理论上可以继续扩展,就得修改上面的宏了
template<char... T>
struct router {
  char name[sizeof...(T) + 1] = { T..., 0 };
  void api(const char* c) {
	std::cout << name << c << '\n';
  };
  void printf() { std::cout << name << '\n'; };
};
int main() {
  router<R("/api")> r;
  r.printf();//输出 /api
  r.api("/hello");//输出 /api/hello
  return 0;
}
//这是实现一个类似于class装饰器的功能,不过模板里面只能放字符串,如果有更好的方案欢迎在下方留言讨论

那么道理可想而知了,利用宏递归,把传入的字符串第一位置开始,取出字符串下标位置的字符,然后进行展开,默认连接的位宽无需全部遍历,多余的直接丢弃,若是传入字符串长度不够,余下的也会被'\0'填满。

实际上呢,看上去也是正常的,如果想要支持更多的宽度,可以自行扩展上面的宏。 

 c++不得不说是很优秀的语言,利用宏+模板,就可以让模板中传入字符串,功能十分强大,非常像其他语言的装饰器。