Ma perché avrebbe vincolato essere progettati in modo tale che questo compila:
auto g = std::bind(&Foo::baz, &foo);
posso chiamare f
, ma non posso mai chiamare g
. Perché perfino farlo compilare?
Il Boost.Bind FAQ dice che Boost.Bind di solito diagnosticare tali errori in "tempo legare" (vale a dire sulla linea in cui si chiama bind
). Tuttavia la norma non richiede che per std::bind
, invece di avere la seguente nella Richiede elemento per std::bind
:
INVOKE (fd, w1, w2, ..., wN)
(20.9.2) deve essere un'espressione valida per alcuni valori w1, w2, ..., wN, dove N == sizeof...(bound_args)
.
Ciò significa che il codice viola la precondizione della funzione, che si traduce in un comportamento non definito. L'implementazione della libreria standard non è obbligata a verificare le violazioni di precondizione, questo è il tuo lavoro. La libreria non ha il divieto di controllarli, quindi sarebbe conforme per un'implementazione rifiutarla, come fa Boost.Bind. Vorrei fare una richiesta al tuo rivenditore di librerie chiedendo loro di diagnosticare espressioni di binding non valide dove è possibile farlo, come un miglioramento della "Qualità di implementazione".
perché non solo hanno il pass di default tutti gli argomenti nel giusto ordine, senza dover specificare esso?
Posso pensare a due ragioni.
In primo luogo, il comportamento della chiamata involucro creato da bind
è far cadere gli argomenti che non corrispondono ad un segnaposto, in modo da poter chiamare x(1, 2, 3)
e lo hanno ignorare tutti gli argomenti e chiamare foo.bar()
. Questo fa parte di un modello generale in cui è possibile eseguire il wrapping di una funzione N-arity utilizzando bind
per creare un call wrapper con un'arità completamente diversa che potrebbe aggiungere argomenti, rimuoverli, correggerne alcuni a valori limite specifici, ecc.Sarebbe impossibile avere x(1, 2, 3)
rilasciare tutti gli argomenti se il comportamento predefinito quando non si utilizzano segnaposti nell'espressione di bind era di inoltrare tutti gli argomenti.
In secondo luogo, è più coerente richiedere sempre di essere espliciti su quali argomenti si desidera passare in quale ordine. In generale, avrebbe senso passare tutti gli argomenti di invocazione quando non ci sono argomenti associati, altrimenti come dovrebbe bind
sapere se passare gli argomenti di chiamata prima o dopo gli argomenti associati?
ad es. data
struct X {
void f(int, int) { }
} x;
auto h = bind(&X::f, &x, 1);
h(2);
Se la chiamata a h(2)
risultato x.f(1, 2)
o x.f(2, 1)
? Poiché il comportamento corretto quando ci sono argomenti associati non è ovvio, l'inoltro automatico di tutti gli argomenti quando non ci sono segnaposti usati ha senso solo quando non ci sono argomenti vincolati (perché quindi non c'è alcun dubbio sul fatto che gli argomenti associati debbano venire prima o ultimi) , che è un caso abbastanza speciale. Cambiare una caratteristica significativa dell'API per lavorare con quel caso speciale sarebbe di valore discutibile, specialmente quando rende impossibile il caso x(1, 2, 3)
->foo.bar()
.
Una soluzione alternativa è quella di continuare che gli utenti debbano essere esplicito su ciò che vogliono, ma fornire un modo esplicito per dire "solo in avanti tutto", come proposto da Tomasz Kamiński in N4171 che sarà discusso in C++ riunione del comitato prossima settimana. Il _all
segnaposto risolve il problema di decidere se gli argomenti di invocazione dovrebbero venire prima o dopo gli argomenti legati, perché si può esplicitamente dire se si desidera bind(f, arg1, arg2, std::placeholders::_all)
o bind(f, std::placeholders::_all, arg1, arg2)
o anche bind(f, arg1, std::placeholders::_all, arg2)
Probabilmente perché non v'è alcun modo per ottenere il numero di argomenti di una funzione altrimenti, il che significa che l'oggetto funzione generato dovrebbe consentire * qualsiasi * numero di argomenti, incluso nessuno, che porterebbe a un comportamento indefinito se (ad esempio) 'g' è stato" chiamato "senza argomenti. –
Penso che 'std :: placeholders' esegua due funzioni, 1. come dici tu, indirizzano gli argomenti da source a sink, 2. indicano quanti argomenti sono richiesti. – Niall
Le librerie di boost possono avere più delle motivazioni di progettazione originali relative a 'bind'. – Niall