2401d,d命名参数的状态
原文
从dmd2.103开始,已根据DIP1030实现结构字面和普通函数(包括重载)的命名参数.但,让它与模板函数一起工作比期望的更难,因此不得不延迟到以后版本.
我知道人们不喜欢半生不熟/未完成功能,所以不想通过添加它到更新日志中,来宣布它.考虑过引入-preview=namedArguments开关,但随后该开关会很快变成弃用状态,且dub包可能需要有条件地指定该开关以支持dmd2.103和更新版本.
因此静默地放在编译器中会更简单,但回想起来,它最终引起了混乱,如:24241问题,所以下次不会再这样做了.
进展
可在项目页这里,查看命名参数实现状态.一直想在2023年底前至少完成命名函数参数(不是命名模板参数),但可惜没有成功.
因为参数类型(可是元组)和参数赋值间有循环依赖,模板让我卡住了一段时间:
1,解析命名参数的函数需要函数签名.
2,函数签名是通过推导模板参数创建的.
3,由(命名)函数参数推导模板参数
好消息是:找到了一个满意方法,且有个很快合并的有效拉请.
但是,实现所有这些操作时,遇见了DIP1030文本未涵盖的各种歧义/边角情况,可能会用你的输入.
空元组值
alias AliasSeq(T...) = T;
int f(int x, int y) { return 0; }
int v = f(y: AliasSeq!(), 1, 2);
目前,带有空元组的y命名参数按空折叠,并且用(x,y)赋值(1,2).
这是否是个错误?
是否应该赋值1给y?
(.1).
按名重载
使用命名参数,可按名消除有相同类型重载的歧义:
string f(T)(T x) { return "x"; }
string f(T)(T y) { return "y"; }
static assert(f(x: 0) == "x");
static assert(f(y: 0) == "y");
但是,这两个模板函数,最终有完全相同类型.DIP1030指定参数名不是装饰的一部分,从而导致运行时符号冲突:
void main()
{writeln(f(x: 1)); //xwriteln(f(y: 1)); //也是x
}
在找到匹配重载后,编译器是否应该重试所有其他不带命名参数的重载以避免该情况,或是否应该因为首先看到它,实例化x变体,然后因为之前已看到过装饰名,拒绝实例化y.
(.2)
元组参数
目前无法按名分配元组参数:
alias AliasSeq(T...) = T;
int f(AliasSeq!(int, int) x) { return 0; }
//扩展为:
//int f(int __param_0, int __param_1) { return 0; }
//所以失败了.
int v = f(x: 1, 2);
可更改它,使其扩展到:
int f(int x, int __param_1)
但考虑在参数列表时,类型元组就已有名字:
int f(int x, int y) { return 0; }
static if (is(typeof(f) T == __parameters)) {}
pragma(msg, T); //(整`x`,整`y`)
int g(T) {return 0;}
static assert(g(x: 3, y: 5) == 0); //目前工作
int h(T z) {return 0;}
static assert(h(z: 3, 5) == 0); //失败,是否应工作?
第一个参数应该叫x,z,还是都?
注意:按错误设置h()声明将是个重大更改.
(.3).
转发
这在实现中没有,但TimonGehr在Discord上指出了这一点.
是否可转发命名参数,考虑:
import std.stdio;
int f(int x, int y);
auto logAndCall(alias f, T...)(T args)
{writeln(args);return f(args);
}
logAndCall!f(y: 1, x: 0);
名字是否传播到Targs参数?是,那就不干净了:
考虑叫writeln的参数,它会劫持函数调用!
也许可允许其他方式访问名字,如args.x.但是,如果有另一个
(T args, string file)
参数,则被调函数就不能有叫file的参数.
命名值序列
因此,如果不能隐式地给出T...的名字,是否可显式给出?已看到__parameters类型元组可有名字,这可扩展到值序列:
logAndCall!f(args: AliasSeq!(y: 1, x: 0));
但是,此语法对命名模板参数有歧义:根据DIP1030,这应该试设置AliasSeq模板的y和x模板参数.是否可转发命名参数?
dip1030
:.1
两个可能错误:
1,别名序列为空.
2,参数太多.
.2似乎应该已检查过了.
但如果没有,我想臭但正确的方法是肯定的,请试使用带有命名参数的参数列表来避免命名参数.
否则不能继续检查,一次检查一次迭代,而不是2次.只允许匹配1个.
.3我会选择z.因为它是个聚集.
所以当前行为是正确的.
否则,它会更令人惊讶.
目前不支持转发参数名.
目前对别名模板参数,唯一方法是''__traits(identifier,param)''.
语言是缺乏的,在解决该问题前,不应把命名参数塞进去.如果想要它,需要一个DIP.