2009-03-14 13 views
7

mi stavo chiedendo se ci fosse un modo per farlo in C++?Mappa della funzione boost di diversi tipi?

void func1(const std::string& s) 
{ 
std::cout << s << std::endl; 
} 

void func2(int me) 
{ 
std::cout << me << std::endl; 
} 

int main() 
{ 
std::map<std::string, boost::function<???> > a_map; 

a_map["func1"] = &func1; 
a_map["func1"]("HELLO"); 

} 

C'è un modo per fare ciò che ho sopra utilizzando la funzione Boost e una mappa?

+0

supponga è possibile memorizzare i valori e le funzioni nella cartina, come si desidera l'accesso di mappare elementi? – bayda

risposta

2

Ci sono modi per memorizzare le funzioni, il problema è che, per poter chiamare la funzione con l'argomento desiderato, dovresti conoscere il chiamare comunque la firma della funzione, e se si dispone di tali informazioni, si potrebbe anche utilizzare mappe separate o utilizzare un oggetto più complicato di boost :: function.

Se siete disposti a fare un po 'di lavoro e hanno un numero finito di firme, si può solo fare qualcosa di simile:

class MultiFunc 
{ 
protected: 
    MultiFunc() {} 

public: 
    typedef void (*stringFunc)(const std::string&); 
    typedef void (*intFunc)(int); 

    static MultiFunc *Create(stringFunc function); 
    static MultiFunc *Create(intFunc function); 

    virtual void operator()(const string &) { throw exception(); } 
    virtual void operator()(int) { throw exception(); } 
    virtual ~MultiFunc(); 
}; 

class MultiFuncString : public MultiFunc 
{ 
private: 
    stringFunc Function; 
public: 
    MultiFuncString(stringFunc function) : Function(function) {} 
    virtual void operator()(const string &arg) { Function(arg); } 
}; 

class MultiFuncInt : public MultiFunc 
{ 
private: 
    intFunc Function; 
public: 
    MultiFuncInt(intFunc function) : Function(function) {} 
    virtual void operator()(int arg) { Function(arg); } 
}; 

MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function) 
{ 
    return new MultiFuncString(function); 
} 
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function) 
{ 
    return new MultiFuncInt(function); 
} 

void func1(const std::string& s) 
{ 
std::cout << s << std::endl; 
} 
void func2(int me) 
{ 
std::cout << me << std::endl; 
} 

int main() 
{ 
    map<string, MultiFunc *> a_map; 
    a_map["func1"] = MultiFunc::Create(&func1); 
    (*a_map["func1"])("Hello"); 
    a_map["func2"] = MultiFunc::Create(&func2); 
    (*a_map["func2"])(3); 

    // Remember to delete the MultiFunc object, or use smart pointers. 
} 

Questo uscite:

 
Hello 
3 

Purtroppo, non puoi creare funzioni virtuali basate su modelli o puoi facilmente generalizzare tutto questo.

2

Probabilmente non è possibile utilizzare std::map poiché è un contenitore omogeneo. Prova, qualcosa come boost::variant (supportano il pattern visitatore) o boost::tuple

+0

boost :: variante è la strada da percorrere qui. L'ho fatto nel codice e funziona benissimo. In poche righe (di MPL) Appoggio una mappa di int, float, double, String e un function0 di ciascuno di questi tipi. –

0

negozio interfacce:

struct IStringData 
{ 
    virtual std::string get() const = 0; 
    virtual ~IStringData() {} 
}; 

e fare implementaions, uno sarà solo tenere il valore della stringa, altre implementazioni conserverà il functor, forse avrai altre implementazioni in futuro.

0

No. Non puoi. Poiché boost :: function non è polimorfico, si rompe lì. (Prende un set fisso di tipi di argomenti.)

Si parlava di lavoro in quella direzione nella mailing list di boost, però, quindi cerca negli archivi e vedi se c'è del codice che potresti fare.

Una soluzione consiste nell'utilizzare la funzione boost :: ma poi è necessario aggiungere alla mappa non le vere funzioni (es. Func1/func2) ma le funzioni di invio che estrae il tipo dal any-container e chiama la funzione reale . (E balla se è sbagliato, proprio come in qualsiasi langugage dinamico.)

2

Quello che stai cercando di fare sembra un po 'strano. Normalmente, un contenitore dovrebbe essere una raccolta di tipi astratti o oggetti o funzioni con la stessa firma. Altrimenti, come sapresti come chiamare la funzione quando stai iterando il contenitore? Mi piace rendere il contenitore una raccolta di oggetti funzione con una firma conosciuta, quindi utilizzare Boost.Bind per archiviare le chiusure che chiamano la funzione con argomenti aggiuntivi.

Ad esempio:

typedef boost::function<void, void> Function; 
typedef std::map<std::string, Function> Functions; 

Functions functions: 

void foo() 
{ 
    ... 
} 

functions["foo"] = foo; 

void bar(std::string &s) 
{ 
    ... 
} 

// binds the value "hello" to the s parameter 
functions["bar"] = boost::bind(bar, "hello");