2016-07-30 1 views
2

ダックタイピングでUFCSを使用することはできますか?この場合、fooはダックタイプTestBのbaz関数を実行できませんでした。UFCSでダックタイピング

module a; 

struct TestA{ 
    void baz(){ 
     import std.stdio; 
     writeln("Test A"); 
    } 
} 

void foo(T)(auto ref T t){ 
    t.baz(); 
} 

module b; 

struct TestB{} 

void baz(ref TestB b){ 
    import std.stdio; 
    writeln("Test B"); 
} 

import a; 
import b; 
void main() 
{ 
    auto testa = TestA(); 
    auto testb = TestB(); 
    testb.baz(); // works 
    foo(testa); // works 
    foo(testb); // doesn't work 
} 

答えて

2

構造体TestBにはメンバ関数bazはありませんが、無料の機能baz(ref TestB)はモジュールbでもあります。モジュールaの関数fooは、このフリー関数bazを知らないので、TestBが与えられたときには呼び出されません。この問題を解決するには、のbをインポートできます。

void foo(T)(auto ref T t){ 
    import b; //alternatively, import b : baz; 
    t.baz(); 
} 
+0

しかしこれは、ufcs関数を使って新しい型を追加したい場合は、いつも 'foo'が変更されることを意味します。それを避ける方法はありますか? –

+0

私は特定の型の 'foo'を特化してからufcs関数をインポートすることができたと思いますが、それは非常にハッキリです。 –

+0

問題はUFCSがあなたのスコープから関数が見えている場合にのみ機能するということです。あなたが持っていたのは: --- ad --- void foo(T)(auto ref T obj){writeln( "General "); } --- b.d --- void foo(T:string)(自動参照オブジェクト){writeln( "Special"); } --- main.d --- void main() { import a.d; foo( "bar");特別な関数がmain.dには知られていないので、これは "General"を出力します。 } –

2

イントロスペクションの力はどうですか? Gassaの役に立つコメントの後の答えを更新しました:

executor!"baz"(testa); 
executor!"baz"(testb); 
executor!"baz"(testa, my, other, function, args); 
// ... 

編集のように使用することができ

auto executor(string member, T, Args...)(auto ref T t, Args args) 
{ 
    import std.traits : hasMember; 
    static if(hasMember!(T, member)) 
     mixin("return t." ~ member ~ "(args);"); // t.baz() 
    else 
    { 
     import std.traits : moduleName; 
     mixin("import " ~ moduleName!T ~ ":" ~ member ~ ";"); // free function and struct need to be in the same module 
     mixin("return " ~ member ~ "(t, args);"); // baz(t) 
    } 
} 

+1

I * think *フリーな関数を使ってUFCSを使うことがポイントでした。その解決策は、UFCSがどこで行われても、そのような自由な関数をモジュールに入れてインポ​​ートすることです - 配列をランダムに扱うためにはstd.rangeと同じようにアクセス範囲。 – Gassa

関連する問題