2012-10-01 11 views
6

Non riesco a capire come utilizzare la funzione Memoize all'interno di una classe.Come uso std.functional.memoize all'interno di una classe?

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

Questo dà un errore quando si tenta di compilare: Errore: necessita 'questo' per accedere membro slowFunc

Come potrei fare per fare questo lavoro?

+0

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

+0

Ancora ottenere lo stesso errore durante la compilazione di – WelshDragon

risposta

6

In realtà non supporta ancora questo. Potremmo presentare una richiesta di miglioramento. Ecco la mia implementazione sperimentale:

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

I commenti sui tempi sono ovviamente per la mia macchina. :)

+0

Btw questo non è semanticamente sicuro. I metodi hanno bisogno del riferimento "this" perché in genere devono cercare lo stato della classe interna (ad esempio i campi delle classi). Se lo stato cambia tra le chiamate, il risultato dell'hash non verrà aggiornato e otterrai risultati non aggiornati. Ma forse ci sono casi d'uso legittimi per la memorizzazione (mi vengono in mente i metodi @pure). Miglioramento archiviato come: http://d.puremagic.com/issues/show_bug.cgi?id=8743 –

+0

C'è un modo per cancellare l'hash interno, ma si dovrebbe fare un controllo booleano su ogni invocazione. Ad esempio: http://dpaste.dzfl.pl/abb6086f –

+0

Capito: http://dpaste.dzfl.pl/4ba280c7 –

Problemi correlati