2013-04-23 13 views
9

Stavo giocando a ardo con std :: function e std :: bind e ho notato qualcosa di non intuitivo e mi piacerebbe capirlo meglio.Informazioni su std :: function e std :: bind

Ad esempio:

void fun() 
{ 
} 

void hun(std::string) 
{ 
} 

int main() 
{ 

    function<void(int)> g = &fun; //This fails as it should in my understanding. 

    function<void(int)> f = std::bind(fun); //This works for reasons unknown to me  
    function<void(int, std::string)> h = std::bind(hun); //this doesn't work 

return 0; 
} 

Come è possibile associare un function<void(int)> ad una funzione che è void(). Potrei quindi chiamare f (1) e divertirmi(). Mi piacerebbe capire come è fatto. Entrare nell'implementazione di Microsoft Visual Studio 2012 mi ha fatto perdere in un mare di macro illeggibili. ecco perché chiedo questa domanda qui.

+0

Sto usando l'edizione Express vs2012. – Alex

+0

puoi consigliare un sito simile? – Alex

+0

Compila con _clang_ e _g ++ _ entrambi. +1, situazione interessante. – soon

risposta

7

Se non si utilizzano i segnaposto di argomento (_1, _2, ...), tutti gli argomenti passati all'oggetto funzione restituito da std::bind verranno semplicemente scartati. Con:

std::function<void(int)> f = std::bind(fun, std::placeholders::_1); 

Ottengo un errore (lungo e brutto) come previsto.

Per le persone interessate nello standard:

§20.8.9.1.2 [func.bind.bind]

template<class F, class... BoundArgs> 
*unspecified* bind(F&& f, BoundArgs&&... bound_args); 

p3 Restituisce: Una chiamata di inoltro involucro g con un tipo di risultato debole (20.8.2). L'effetto di g(u1, u2, ..., uM) è INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type), dove cv rappresenta il cv -qualifiers di gei valori ei tipi degli argomenti legati v1, v2, ..., vN vengono determinati come specificato di seguito.

p10 I valori degli argomenti legati v1, v2, ..., vN ei loro tipi corrispondenti V1, V2, ..., VNdipendono dal tipo TiD derivati ​​dalla chiamata a bind e la cv -qualifiers cv della chiamata involucro g come segue:

  • se TiD è reference_wrapper<T>, l'argomento è tid.get() e il suo tipo Vi è T&;
  • se il valore di is_bind_expression<TiD>::value è true, l'argomento è tid(std::forward<Uj>(uj)...) e il suo tipo è result_of<TiD cv (Uj...)>::type;
  • se il valore j di is_placeholder<TiD>::value non è zero, l'argomento è std::forward<Uj>(uj) e il suo tipo Vi è Uj&&;
  • in caso contrario, il valore è tid e il tipo Vi è TiD cv &.
+0

Oltre a ciò, anche se std :: funzione f = std :: bind (divertimento); compila. Non è possibile chiamare effettivamente f: f(); non riesce a compilare. –

+1

@PeterR: Ovviamente, poiché la firma di 'f' richiede un argomento. :) – Xeo

6

Il wrapper chiamata inoltro generato da una chiamata alla funzione template bind può accettare qualsiasi numero di parametri aggiuntivi; questi saranno ignorati. L'arità effettiva e la firma minima di un'espressione bind sono determinate dagli placeholder s utilizzati nella sua costruzione e da quali argomenti richiamabili sono associati.