OK,我想要做的是神仙复杂,但我会试着解释.
比方说,我们希望(在编译时)所有derivedMembers类的someClass.那我们就是这样做的:
const string[] methods = [__traits(derivedMembers,someClass)];
Run Code Online (Sandbox Code Playgroud)
现在,我们怎么能得到someClass的"someClass"?(是的,它的字符串表示).
让我解释一下我正在尝试做的事情:
我想创建一个"中间"函数,它接受一个function在一个特定的(预定义的)组类名作为参数(具有参数数组一起)并调用适当的功能从可用静态方法的列表.喜欢execute("someFunc",["one","two","three"]);.
下面是完整的(测试)的代码:
class Math {
static string noArgs(string[] s) { writeln(s); return ""; }
static string withOneArg(string[] s) { writeln(s); return ""; }
static string withTwoArgs(string[] s) { writeln(s); return ""; }
}
string cases()
{
string ret = "";
const string[] methods = [__traits(derivedMembers,Math)];
foreach (string s; methods)
{
ret ~= "case \"" ~ s ~ "\": return Math."~s~"(params);";
}
return ret;
}
string execute(string what, string[] params)
{
switch (what)
{
mixin(cases());
default: break;
}
return "";
}
Run Code Online (Sandbox Code Playgroud)
与上面的代码的麻烦是,它仅查找的方法Math.我怎么可以改变它,在一个优雅d友好的方式,所以它会经历像类数组的形式[Math,String,SomethingElse]-它并不必须是变量(我们需要在编译时反正)?
更新:
试图沿着线的东西:
const string[] methods = [__traits(derivedMembers,mixin("Math")];
Run Code Online (Sandbox Code Playgroud)
但它抱怨说Cannot interpret Math at compile time.
更新2:
此外,尝试使用,Object.factory("Math")但它仍然无法正常工作.(也许我只是创建的实例Math类?)
让我改写一下,向你展示一些很酷的技巧:
import std.stdio;
class Math {
static string noArgs(string[] s) { writeln(s); return ""; }
static string withOneArg(string[] s) { writeln(s); return ""; }
static string withTwoArgs(string[] s) { writeln(s); return ""; }
}
class String {
static string oneArg(string[] s) { return null; }
}
string execute(string what, string[] params) {
import std.string;
auto parts = what.split(".");
auto className = parts[0];
auto methodName = parts[1];
import std.typetuple;
switch(className) {
default: assert(0, "unknown class");
foreach(possibleClass; TypeTuple!(Math, String)) {
case possibleClass.stringof:
switch(methodName) {
default: assert(0, "unknown method");
foreach(memberName; __traits(derivedMembers, possibleClass)) {
case memberName:
return __traits(getMember, possibleClass, memberName)(params);
break;
}
}
break;
}
}
assert(0);
}
void main() {
execute("Math.withOneArg", ["cool"]);
execute("String.oneArg", ["cool"]);
}
Run Code Online (Sandbox Code Playgroud)
请注意,根本没有mixin使用任何表达式.我没有从字符串中获取类的实例,而是创建了TypeTuple我想要使用的所有类.这是优选的,mixin因为当在不同的范围内使用时,它不太可能找到名称类; 如果possibleClasses是execute来自不同模块的编译时参数,则类列表仍然有效,而字符串列表将看到未定义的标识符错误,因为库模块不会导入您的用户模块.
另一个mixin我删除是产生的案件之一.这看起来很疯狂,但在D中是允许的:如果你有一个编译时foreach(也就是说,foreach某个内置的某种元组,例如TypeTuple模板参数列表,__traits...... 的结果)你可以实际放置case语句在他们里面!
所以,你所要做的就是switch在你想要比较的运行时变量上写一个常规语句,把foreach它放在你正在搜索的编译时间内的循环中,case that_loop_var:然后繁荣,你就是在做生意.
同样,我使用__traits(getMember)而不是mixin字符串来调用该方法.此解决方案将有助于避免名称冲突,IMO是更清晰的代码.如果需要,它也可能潜在地处理重载(__traits(getOverloads)而不是__traits(getMember),你可以遍历每个,然后匹配参数类型).
最后,允许switch在其他case语句中嵌套es .如果您需要突破外部循环或者switch不需要歧义,可以标记循环和开关,并使用它break label_name_here;来指定要从哪个中断.continue与嵌套循环同上.
顺便说一句,你也可以自动生成包装函数,string[]如果你潜入了std.traits这些参数,它们会转换成其他类型的参数.我希望我的书已经出版了,我在那里写了很长一段时间,并且不想现在写一遍,但是如果你看一下std.traits.ParameterTypeTuple并且ReturnType在同一个模块中,如果你想尝试它就会让你开始.
| 归档时间: |
|
| 查看次数: |
384 次 |
| 最近记录: |