2012-10-01 10 views
6

Nie jestem w stanie dowiedzieć się, jak korzystać z funkcji memoize w klasie.Jak używać std.functional.memoize w klasie?

import std.functional; 

class A { 
    int slowFunc(int a, int b) { 
     return 0; 
    } 

    alias memoize!slowFunc fastFunc; 
} 

void main() { 
    auto a = new A; 
    a.fastFunc(1,2); 
} 

To daje błąd podczas próby kompilacji: Błąd: potrzebę „to”, aby uzyskać dostęp członek slowFunc

Jak bym go o przeprowadzenie tej pracy?

+0

i 'alias memoize! (This.slowFunc) fastFunc;'? –

+0

Nadal pojawia się ten sam błąd podczas kompilowania – WelshDragon

Odpowiedz

6

To jeszcze nie obsługuje tego. Możemy zgłosić prośbę o ulepszenie. Oto moja eksperymentalna implementacja:

import std.stdio; 
import std.traits; 
import std.typecons; 
import std.datetime; 

template isClassStruct(alias fun) 
{ 
    enum bool isClassStruct = (is(fun == class) || is(fun == struct)); 
} 

mixin template memoize(alias fun, uint maxSize = uint.max) 
    if (isClassStruct!(__traits(parent, fun))) 
{ 
    ReturnType!fun opCall(ParameterTypeTuple!fun args) 
    { 
     static ReturnType!fun[Tuple!(typeof(args))] memo; 
     auto t = tuple(args); 
     auto p = t in memo; 
     if (p) return *p; 
     static if (maxSize != uint.max) 
     { 
      if (memo.length >= maxSize) memo = null; 
     } 

     mixin("auto r = this." ~ __traits(identifier, fun) ~ "(args);"); 
     memo[t] = r; 
     return r; 
    }  
} 

class A 
{ 
    int slowFunc(int a, int b) 
    { 
     int result; 
     foreach (_; 0 .. 1024) 
     { 
      result += a; 
      result += b; 
     } 
     return result; 
    } 

    mixin memoize!slowFunc fastFunc; 
} 

enum CallCount = 2048; 

void main() 
{ 
    A a = new A; 

    auto sw1 = StopWatch(AutoStart.yes); 
    foreach (x; 0 .. CallCount) 
    { 
     a.slowFunc(100, 100); // 11232 usecs 
    } 
    sw1.stop(); 
    writeln(sw1.peek.usecs); 

    auto sw2 = StopWatch(AutoStart.yes); 
    foreach (x; 0 .. CallCount) 
    { 
     a.fastFunc(100, 100); // 302 usecs 
    } 
    sw2.stop(); 
    writeln(sw2.peek.usecs); 
} 

Komentarze dotyczące czasu dotyczą oczywiście mojej maszyny. :)

+0

Btw to nie jest semantycznie bezpieczne. Metody wymagają odwołania "this", ponieważ zazwyczaj muszą sprawdzać stan wewnętrznej klasy (np. Pola klasy). Jeśli ten stan zmieni się między połączeniami, nie zostanie zaktualizowany wynik skrócony, a otrzymasz z powrotem nieaktualne wyniki. Ale może istnieją uzasadnione przypadki użycia do pamiętania (@pure metody przychodzą na myśl). Enhancement złożony jako: http://d.puremagic.com/issues/show_bug.cgi?id=8743 –

+0

Istnieje sposób, aby wyczyścić wewnętrzny hasz, ale trzeba by zrobić Boolean sprawdzić na każdym inwokacji. Na przykład: http://dpaste.dzfl.pl/abb6086f –

+0

Wyliczyłem: http://dpaste.dzfl.pl/4ba280c7 –

Powiązane problemy