重载外部函数以在单独的模块中使用

时间:2013-08-19 18:30:27

标签: d

我想做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特化的行为方式。

3 个答案:

答案 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上测试了一般方法,它似乎有效。

哦,还有一个缺点,就是这样写的只处理左值引用,但可以修复模块wrapwrappers重载的方法。