2016-07-30 27 views
2

Ist es möglich, UFCS mit Ente Typisierung zu verwenden? In diesem Fall konnte foo TestB 's baz function nicht ducken.Ducktyping mit 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 
} 

Antwort

2

Die struct TestB hat keine Mitgliedsfunktion baz, aber es ist eine freie Funktion baz(ref TestB) in Modul b. Die Funktion foo in Modul a weiß nicht über diese freie Funktion baz, so dass es nicht aufgerufen wird, wenn TestB gegeben. Um dies zu beheben, können Sie b in Modul a importieren.

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

Aber das bedeutet, dass 'foo' jedes Mal geändert werden muss, wenn ich einen neuen Typ mit einer ufcs-Funktion hinzufügen möchte. Gibt es eine Möglichkeit, das zu vermeiden? –

+0

Ich denke, ich könnte 'foo' für einen bestimmten Typ spezialisieren und dann die ufcs-Funktion importieren, aber das scheint sehr hacky zu sein. –

+0

Das Problem ist, dass UFCS nur funktioniert, wenn die Funktionen aus dem Bereich, in dem Sie sich befinden, sichtbar sind. Wenn Sie hatten: --- ad --- void foo (T) (automatische Ref T obj) {writeln ("General "); } --- b.d --- void foo (T: string) (automatische Ref T obj) {writeln ("Special"); } --- main.d --- void main() { importieren a.d.; foo ("bar"); // dies wird "General" ausgeben, da die spezialisierte Funktion nicht bekannt ist. } –

2

Wie wäre es mit der Kraft der Introspektion?

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

bearbeiten

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) 
    } 
} 

die wie

verwendet werden können: aktualisiert die Antwort nach Gassa ist hilfreich Kommentar.

+1

Ich * denke * der Punkt war, UFCS mit einer freien Funktion zu verwenden, und die Lösung ist, solche freien Funktionen in einem Modul zu behalten und zu importieren, wo immer UFCS stattfindet - ähnlich std.range ist erforderlich, um Arrays als zufällig zu behandeln Zugriffsbereiche. – Gassa