c++的缺点
是什么,就是元编程
太麻烦.c++
必须要有根本性的改变,才能
让元编程更方便.虽然c++20
已经不错了.d自定义打印格式
传统:
struct S
{
... // my sooper sekret data here!
string toString() const pure @safe
{
// 最小化构造串
auto app = appender!string();
... //数据转为串
return app.data;
}
}
void main()
{
auto s = S();
... //处理s
writeln(s);
}
变化
struct S
{
void toString(scope void delegate(const(char)[]) sink,
FormatSpec!char fmt) const
{//其实就是加几个模板参数.
switch(fmt.spec)
{
// Look, ma! I invented my own format specs!
case 'i':
// output first format to sink
break;
case 'j':
// output second format to sink
break;
case 's':
// output boring default string format
break;
default:
throw new Exception("Unknown format specifier: %" ~ fmt.spec);
}
}
}
注意:使用FormatSpec!char作为格式化为UTF-8字符串的最常见情况。如果您还希望以16位wstring或32位dstring实现格式化,则必须实现以FormatSpec!wchar或FormatSpec!dchar作为参数的toString函数
更好的C
:
import core.stdc.stdio;
extern(C):
int main()
{
printf("1 + 1 = %d!\n", 1 + 1);
return 0;
}
$ dmd -betterC example.d
$ ./example
1 + 1 = 2!
将枚举类型的名称作为数组
:
enum State
{
stopped,
starting,
running,
stopping,
}
string[] state_names = [__traits(allMembers, State)];
一篇文章对比c++与d的元编程
:在此
什么是编译时查找
.编译时查找已知的串,就是这个串,我编译时就已经知道了,类似手写串.而不是运行时才知道.因而这时
根本就没必要再进行运行时查找
了.就相当于串作为模板的参数,因为串已知.所以模板<串>
就是个固定已知的函数了,没必要再查找这个函数
了.直接调用即可.
直接看d语言的实现.c++
如果不进行一番大的改造,是不能优雅实现的,借助于hana
,但仍不是很漂亮.因为反射及很多
还未实现.
D的元编程为什么厉害,就是把一切符号当作占位符
.最后填占位符
就是了.其实现代的宏编程
也是这个玩意.最后都是AST(语法树)
.
void main() {
EventSystem!("foo", "bar", "baz") events;//编译时字符串与常规串一样.
events.on!"foo"(() { writeln("foo triggered!"); });
events.on!"foo"(() { writeln("foo again!"); });
events.on!"bar"(() { writeln("bar triggered!"); });
events.on!"baz"(() { writeln("baz triggered!"); });
// events.on!"unknown"(() {}); // compile error!
events.trigger!"foo";
events.trigger!"baz";
events.trigger("bar"); // overload for dynamic dispatch
// events.trigger!"unknown"; // compile error!
}
//接着
void on(string event)(Callback c) {
enum index = staticIndexOf!(event, events);//枚是关键
static assert(index >= 0,
"trying to add a callback to an unknown event: " ~ event);
callbacks_[index] ~= c;
}
void trigger(string event)() {
enum index = staticIndexOf!(event, events);//枚
static assert(index >= 0,
"trying to trigger an unknown event: " ~ event);
foreach (callback; callbacks_[index])
callback();
}
d有两个编译时阶段:一,ast树
,二,ctfe
.前面有文章.
void trigger(string event) {
foreach (i, e; events) {
if (event == e) {
foreach (c; callbacks_[i])
c();
return;
}
}
assert(false, "trying to trigger an unknown event: " ~ event);
}
struct Entity(arg...)
if (arg.length == 1)
{
static if (is(arg[0])) {
alias Type = arg[0];
} else static if (is(typeof(arg[0]) T)) {
alias Type = T;
enum value = arg[0];
}
}
这样来用Entity!"foo"()来创建对象Entity!double(),简化:
enum c(arg...) = Entity!arg();
static assert(is(c!int.Type == int));
static assert(is(c!"foo".Type == string));
static assert(c!"foo".value == "foo");
static assert(c!42.value == 42);
下面:
我们需要一种可以存储不同类型的值的东西(例如std.typecons.Tuple,其中键是类型或编译时值,其实例化如下:
struct Bar {}
Map!(//存储不同类型的键与值.
"foo", int, // string "foo" maps to a value of type int
Bar, string, // type Bar maps to a value of type string
"한", string[]) map; // string "한" maps to a value of type string[]
我们需要将交织键和值类型分开,并声明值本身的存储:
struct Map(spec...) {//这就是个把整个类型序化,然后对这个类型序列求值.
alias Keys = Even!spec;//偶数项,编译时求类型值
alias Values = Odd!spec;//所有奇数项类型.
Values values;
实现见下:
template Stride(size_t first, size_t stride, A...) {
static if (A.length > first)
alias Stride = AliasSeq!(A[first], Stride!(stride, stride, A[first .. $]));//这里,又是个静态递归.stride为步数.估计就是递归取第几项,相当求所有余3等等的序列.只不过是静态编译时求值.
else
alias Stride = AliasSeq!();//别名序列.序列这个玩意儿还是不错
}
alias Odd(A...) = Stride!(1, 2, A);//这个其实就是个索引,2%1的
alias Even(A...) = Stride!(0, 2, A);//第2项的第0项,2%0的项.与我前面
使用:
// 初化
auto map =
Map!("foo", int, Bar, string, "한", string[])(
42, "baz", ["lorem", "ipsum", "dolor"]);
//迭代键
foreach (K; map.Keys)
writeln(K.stringof);
//迭代值类型
foreach (V; map.Values)
writeln(V.stringof);
// 迭代值
foreach (value; map.values)
writeln(value);
重载in
.最后了,坚持下去.
static bool opBinaryRight(string op, Key...)(Entity!Key key)
if (op == "in")
{//静仅取决于编译时,二分右,
enum index = staticIndexOf!(Key, Keys);//即某个类型是否在类型序列中.
return index >= 0;
}
static assert(c!"foo" in map);
static assert(c!Bar in map);
static assert(c!"한" in map);
static assert(c!42 !in map);
private template IndexOf(alias Key) {
enum IndexOf = staticIndexOf!(Key, Keys);
static assert(IndexOf >= 0,
"trying to access a nonexistent key: " ~ Key);
}//包装.
auto opIndex(Key...)(Entity!Key key) const {
return values[IndexOf!Key];
}
auto opIndexAssign(T, Key...)(auto ref T value, Entity!Key key) {
return values[IndexOf!Key] = value;
}
auto opIndexOpAssign(string op, T, Key...)(auto ref T value, Entity!Key key) {
return mixin(`values[IndexOf!Key] ` ~ op ~ `= value`);
}//映射的键索引.类似 映[键]
测试:
//编译时查找键的类型/值,运行时比较
map[c!"foo"] = 42; // opIndexAssign
map[c!Bar] = "baz";
map[c!"한"] ~= "lorem"; // opIndexOpAssign!"~"
map[c!"한"] ~= "ipsum";
map[c!"한"] ~= "dolor";
//同样
assert(map[c!"foo"] == 42); // opIndex
assert(map[c!Bar] == "baz");
assert(map[c!"한"] == ["lorem", "ipsum", "dolor"]);