7

私はこれをやりたいと思っています(これでサポートされています)が、小さな問題にぶつかっています(あなたの頭痛が少なく不快でないために骨抜きにされています)。

私がライブラリ ライターで、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); }

このコードの結果は「プリン!」になります。' Wigglytuff !' ではなく印刷されています。これは理にかなっています。なぜなら、 の定義は、そのモジュールで利用できる進化していない非専門化された形式runrunしか見ることができないからです。しかし、私 (およびクライアント コード) は、'Jigglypuff' ではなく 'Wigglytuff' を見たいと思っています。

C++ では、呼び出しnamespace mod_a { ... }の定義を決定しようとするときに、クライアント コードの実行をライブラリ コードと一緒に調べる必要があることを示すために、run の特殊化を回避し、runrunそのような動作に伴うワームの缶を歓迎します。

run関数が意図的にハイジャックされるようにこれを整理するための慣用的な D ウェイはありますか? 具体的には、アドホックな特殊化で C++ のグローバル関数が動作する方法を模倣したいと考えています。

4

3 に答える 3

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); }
于 2013-08-20T19:50:43.597 に答える
1

この例では、ライブラリを作成しているmod_aので、比較的簡単に変更できます。しかし、あなたがライブラリの作者ではない状況について考えずにはいられません。

その場合、ライブラリの実際の作成者はおそらく、あなたがやろうとしていることをただできないことを喜んでいるか、あなたがやろうとしていることを積極的にサポートしたいと思っているでしょう.

ライブラリの作成者が、実装で使用する関数を「ハイジャック」できるようにしてほしいと考えているとします。彼または彼女はおそらくそれについて別の方法で行うでしょう。私は...するだろう。

これは、あなたがリンクしたカプセル化の話が信じている1つの領域であり、ここであなたが望むものとは反対の状況を達成する方法を正確に説明しています。この種のことは、契約プログラミングが必要だと叫んでいます。

ライブラリの作成者として、私はおそらくインターフェイスと、場合によっては抽象クラス、場合によっては 1 つまたは 2 つの具体的な実装を提供し、それを使用して目的を達成できるようにします。他の誰かが、引数として特定の実装を必要とするテンプレートまたはランタイム パラメーターを追加する可能性があります。しかし、他の誰かが遅延文字列デリゲートをミックスに追加する可能性があります。

(私の) 結論: ライブラリの作成者として、あなたが望むことを可能にするオプションがあります。好みのライブラリでそれが不可能な場合は、機能要求を提出することになるでしょう。

于 2013-08-20T20:53:09.473 に答える
0

ミックスインを使用して、検索された名前空間をライブラリ コードからユーザー コードに移動する奇妙な方法を見つけました。ライブラリ作成者の観点からは、これは 1 つの余分な関数と 1 つの追加のテンプレート タイプです。ユーザーの観点からは、モジュールの外側にグローバルな「メソッド」を持つ型のインスタンスごとに 1 つの余分な関数呼び出しと並んで、1 つの余分な (やや面倒な) コード行です。これが言語機能を明示的にオーバーライドする方法であることを考えると、これはかなり良いことだと思います。

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

于 2013-09-16T18:22:30.133 に答える