2012-05-23 8 views
16

Come posso eseguire il bind a una funzione che accetta argomenti predefiniti, senza specificare gli argomenti predefiniti e quindi chiamarla senza argomenti?Posso eseguire il binding a una funzione che accetta gli argomenti predefiniti e quindi chiama?

void foo(int a, int b = 23) { 
    std::cout << a << " " << b << std::endl; 
} 

int main() { 
    auto f = std::bind(foo, 23, 34); // works 
    f(); 


    auto g = std::bind(foo, 23); // doesn't work 
    g(); 

    using std::placeholders::_1; 
    auto h = std::bind(foo, 23, _1); // doesn't work either 
    h(); 

} 
+1

Definire "non funziona". Il codice verrebbe compilato se avessi dato nomi diversi alle variabili. –

+0

perché continui a riassegnare a f? – 111111

+0

@ R.MartinhoFernandes yeah sorry, l'esempio era incompleto. codice aggiornato – inf

risposta

20

In pratica, ogni volta che si scrivere foo(x) il compilatore traduce a foo(x, 23);. Funziona solo se hai effettivamente una chiamata diretta con il nome della funzione. Ad esempio, non è possibile assegnare &foo a void(*)(int), perché la firma della funzione è void(int, int). I parametri predefiniti non fanno parte della firma. E se lo assegni a una variabile void(*)(int, int), le informazioni sul parametro predefinito vengono perse: non puoi sfruttare il parametro predefinito attraverso quella variabile. std::bind memorizza un void(*)(int, int) da qualche parte nelle sue viscere, e quindi perde le informazioni sui parametri di default.

Non c'è modo in C++ di ottenere il valore predefinito di un parametro dall'esterno della funzione, quindi è necessario mantenere manualmente il valore predefinito quando si esegue il binding.

+0

ottimo sfondo, grazie. – inf

8

Penso che potresti simulare il comportamento che desideri utilizzando un lambda.

Qualcosa sulla falsariga di questo:

auto g = [](){ foo(23); }; 

EDIT: Ho appena controllato, e sembra funzionare bene: http://ideone.com/SPSvi

0

Ho due soluzioni:

1 - È possibile sovraccaricare foo () e chiamare l'originale con i valori predefiniti:

void foo(int a, int b) 
{ 
    std::cout << a << " " << b << std::endl; 
} 

inline void foo(int a) 
{ 
    foo(a, 23); 
} 

2 - È possibile utilizzare una variabile statica come predefinito e quindi utilizzarlo nel processo di rilegatura:

static int foo_default_b = 23; 
void foo(int a, int b = foo_default_b) 
{ 
    std::cout << a << " " << b << std::endl; 
} 

auto g = std::bind(foo, 23, foo_default_b); 
g(); 
0

This answer non è d'accordo con la risposta R. Martinho Fernandes'. È infatti possibile utilizzare boost::bind di legarsi ai parametri di default, è solo bisogno di mettere i segnaposto in, come così:

boost::bind<void (int, int)>(foo, _1, _2)(12); 

Ciò richiederà foo(12, 23), come previsto. Anche se non ho provato questo codice specifico, ho fatto qualcosa di simile nel mio codice basato sulla risposta collegata sopra, e funziona in gcc 4.8.5.

Hmm, ho appena notato che si tratta di std::bind, non boost::bind. Non so quali differenze ci siano, se ce ne sono.