Entrambi std::forwarde std::movenon sono altro che cast.
X x;
std::move(x);
Quanto sopra lancia l'espressione lvalue xdi tipo X su un'espressione rvalue di tipo X (un valore x per essere esatti). movepuò anche accettare un valore:
std::move(make_X());
e in questo caso è una funzione di identità: prende un valore di tipo X e restituisce un valore di tipo X.
Con std::forwardte puoi selezionare la destinazione in una certa misura:
X x;
std::forward<Y>(x);
Lancia l'espressione lvalue xdi tipo X su un'espressione di tipo Y. Esistono vincoli su ciò che Y può essere.
Y può essere una base accessibile di X o un riferimento a una base di X. Y può essere X o un riferimento a X. Non è possibile eliminare qualificatori cv con forward, ma è possibile aggiungere qualificatori cv. Y non può essere un tipo che è semplicemente convertibile da X, tranne tramite una conversione Base accessibile.
Se Y è un riferimento lvalue, il risultato sarà un'espressione lvalue. Se Y non è un riferimento lvalue, il risultato sarà un'espressione rvalue (xvalue per essere precisi).
forwardpuò accettare un argomento rvalue solo se Y non è un riferimento lvalue. Cioè, non puoi lanciare un valore in valore. Questo per motivi di sicurezza in quanto ciò porta comunemente a riferimenti sospesi. Ma lanciare un valore in valore è ok e permesso.
Se si tenta di specificare Y su qualcosa che non è consentito, l'errore verrà rilevato al momento della compilazione, non in fase di esecuzione.