我想做this(由this支持),但是我遇到了一个很小的问题(因为你的不那么头疼而不喜欢)。
假设我是一名图书馆作家,我在D档中有这些功能:
module mod_a;
import std.stdio;
void run(T)(T v) { writeln("Jigglypuff!"); }
void runrun(T)(T v) { run(v); }
我在另一个模块中有客户端代码,我尝试重载run
并调用runrun
:
import mod_a;
void run(T:double)(T v) { writeln("Wigglytuff!"); }
void main() { runrun(1.0); }
此代码导致'Jigglypuff!'正在打印而不是'Wigglytuff!',这是有道理的,因为runrun
的定义只能看到其模块中可用的未解决的非特殊化形式。然而,我(和客户代码)希望看到'Wigglytuff'而不是'Jigglypuff'。
在C ++中,我会在run的特化项周围抛出一个namespace mod_a { ... }
来表明在尝试确定runrun
调用的定义时,应该检查客户端代码的运行以及我的库代码,欢迎与此类行为一起出现的蠕虫病毒。
是否有一种惯用的D方式来组织这种方式,以便功能run
可能故意被劫持?具体来说,我想模仿C ++的全局函数与ad-hoc特化的行为方式。
答案 0 :(得分:2)
//untested
module mod_a;
import std.stdio;
void run(T)(T v) if (!is(T : double)) { writeln("Jigglypuff!"); }
void runrun(T)(T v) { run(v); }
import mod_a;
void run(T)() if (is(T : double)) { writeln("Wigglytuff!"); }
void main() { runrun(1.0); }
答案 1 :(得分:1)
在此示例中,您是库mod_a
的创作者,因此修改它会相对容易。但我不禁想到你不是图书馆作者的情况。
在这种情况下,图书馆的实际作者可能会很高兴你不能只做你想做的事情......或者积极地想要支持你想要做的事情。
让我们假设图书馆作家希望你能够“劫持”他/她在实施中使用的功能。他或她可能会采用不同的方式;我愿意。
这是我认为你联系的封装故事和我刚刚阅读的一个领域,描述了如何在这里实现你想要的相反情况。这种类型的东西尖叫它需要合同编程。
作为一名图书馆作者,我可能会为您提供一个界面,可能还有一个抽象类,甚至可能是一两个具体实现,您可以使用它来做您的事情。其他人可能会添加一个模板或运行时参数,需要特定的实现作为参数。然而,其他人可以添加一个懒惰的字符串委托给混合。
(我的)结论:作为一名图书馆作者,您可以选择制作您想要的内容。如果您的首选图书馆无法使用,您可能最终会提交功能请求。
答案 2 :(得分:0)
我发现了一种奇怪的方法,使用mixins将搜索到的库名称库中的命名空间移动到用户代码。从库编写者的角度来看,它是一个额外的功能和一个额外的模板类型;从用户的角度来看,它是一个额外的(有点烦人的)代码行,还有一个额外的函数调用,每个类型的实例在其模块之外具有全局“方法”。考虑到这是一种明确覆盖语言功能的方法,我认为非常好。
module wrappers;
mixin template wrapmix()
{
struct Wrap(T)
{
T* val;
auto opDispatch(string Name, A...) { return mixin("(*val)."~Name~"(a);"); }
}
auto wrap(T)(ref T val) { return Wrap!T(&val); }
}
然后,这用于创建一个类型,用于搜索为调度声明的任何模块。
import mod_a;
import wrappers;
mixin wrapmix; ///< magic
void main() {
double val = 1.0;
runrun(wrap(val)); ///< note the 'wrap' call
}
虽然上面的代码没有经过明确的测试,但我在GDC上测试了一般方法,它似乎有效。
哦,还有一个缺点,就是这样写的只处理左值引用,但可以修复模块wrap
中wrappers
重载的方法。