2012-11-06 12 views
18

Supponiamo che io sono una funzione che prende due argomenti,Perché gli oggetti restituiti da bind ignorano gli argomenti extra?

void f(int x, int y); 

e voglio legare uno di loro. Posso usare std::bind come segue:

auto partiallyBoundF = std::bind(f, 10, _1); 

partiallyBoundF richiede un solo argomento, ma posso chiamarla con più di una. Gli argomenti oltre il primo, non hanno nemmeno bisogno di essere di un tipo che ha un senso:

partiallyBoundF(20, 0); 
partiallyBoundF(0, 44, -99, "Hello", 4.5, true, []{}); 

Qual è lo scopo di oggetti che permettono tornato da bind da passare argomenti extra? Permette di compilare errori di chiamata che verrebbero respinti altrove.

+3

Che compilatore? Direi che questo potrebbe essere solo un compilatore non conforme (perché consentire quegli argomenti aggiuntivi non ha alcun senso e dubito che lo standard lo consenta). Ad esempio, MSVC emula i modelli variadici semplicemente definendo ogni modello variadic per prendere il massimo degli argomenti del modello e impostandoli per default ad alcuni tipi NIL. Forse qualcosa del genere è la causa del tuo comportamento? –

+3

@ChristianRau: fa parte dello standard. Anche questo faceva parte del TR1. 20.8.2/4 rende il commento che l'implementazione prevista è per un operatore() 'variadic-templatized per prendere semplicemente tutto ciò che gli viene passato, indipendentemente dal tipo o dal numero di argomenti. TR1 ha una formulazione simile. – KnowItAllWannabe

+1

Nel tuo caso, f (w1, ..., wN) dove 'N = sizeof ... (bound_args)' (numero di argomenti da associare alla chiamata) deve essere un'espressione valida, vedi 20.8.9.1.2/2 e 20.8.2/1. Modifica: NON disattiva alcun altro modo per chiamarlo. – dyp

risposta

16

Ignorare gli argomenti aggiuntivi è molto più semplice da implementare e può effettivamente essere utile.

In un'implementazione tipica, ad es. libstdC++ (g ++), l'approccio adottato è quello di raccogliere gli argomenti operator() in una tupla e quindi lasciare che gli argomenti di collegamento std::placeholder li estraino come richiesto. L'imposizione del conteggio degli argomenti richiederebbe il conteggio del numero di segnaposto usati, il che sarebbe piuttosto complicato. Si noti che il bind callable può essere un funtore con modelli di chiamata operator() multipli, quindi l'oggetto bind operator() non può essere generato con una singola firma "corretta".

Si noti inoltre che è possibile scrivere:

std::bind(&foo, std::placeholders::_1, std::placeholders::_3); 

cioè ignorando in modo esplicito il secondo argomento all'oggetto bind. Se bind ha applicato il conteggio degli argomenti, è necessario un ulteriore modo per specificare che ad es. anche un quarto argomento doveva essere ignorato.

Per quanto riguarda l'utilità, si consideri vincolante un gestore di segnale membro ad un segnale:

sig.connect(std::bind(&C::on_sig, this, param, std::placeholders::_1)); 

Se sig ha parametri di emissione in più indesiderati, allora sono semplicemente ignorati dall'oggetto bind; in caso contrario, l'associazione dello stesso gestore a più segnali richiederebbe la scrittura di più wrapper di inoltro senza scopo reale.

+3

"più utile" - Ne discuterò. Questo rompe la digitazione forte. E se lo si desidera, questo comportamento potrebbe ancora essere emulato con un rigoroso 'std :: bind' semplicemente usando un proxy functor che accetta argomenti variadici. –

+2

@KonradRudolph un'espressione di bind non * ha * un tipo ben definito nel caso generale, se il suo callable è un functor con più 'operator()' s. – ecatmur

+0

È possibile ignorare un quarto argomento utilizzando un lambda. Non molto carino, però. – dyp

Problemi correlati