¿Bajo qué condiciones std::forward y static_cast son equivalentes?
El enlace http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0644r1.html dice:
Hay dos formas de reenviar una variable: se puede usar std::forward o se puede usar static_cast directamente (como lo hace el operador de reenvío de esta propuesta):
template <class x,="" class="" y="">
decltype(auto) foo(X&& x, Y&& y) {
return std::forward<x>(x)(std::forward<y>(y)); // con std::forward
return static_cast<x&&>(x)(static_cast<y&&>(y)); // con static_cast, exactamente equivalente
}
¿Se aplica “exactamente equivalente” porque X
e Y
son parámetros de plantilla y, por lo tanto, X&&
e Y&&
son referencias de reenvío? ¿O por alguna otra razón?
Supongo que no siempre se aplica, porque si lo hiciera:
1. Esperaría que la documentación de std::forward
lo mencionara, como lo hace la de std::move
;
2. No habría motivo para el aumento del 14% en la velocidad de compilación al reemplazar uno con el otro.
Mi mejor suposición actual es que:
1. std::forward
no se compila en algunos casos en los que static_cast
sí se compila;
2. Pero no viceversa: si std::forward
se compila, también lo hace static_cast
;
3. Si se compila, ambos tienen el mismo resultado.
Pero estoy lejos de estar seguro de que sea correcto.</y&&></x&&>
davy.ai
La afirmación “exáctamente equivalente” se aplica porque
X
eY
son parámetros de plantilla y por lo tantoX&&
eY&&
son referencias hacia adelante. CuandoX
eY
son referencias hacia adelante,static_cast<x&&>(x)
ystd::forward<x>(x)
son exactamente equivalentes.No siempre es el caso de que
std::forward
ystatic_cast
sean exactamente equivalentes. Por ejemplo, siX
no es una referencia hacia adelante, entoncesstd::forward<x>(x)
no se compilará, perostatic_cast<x&&>(x)
sí se compilará. Del mismo modo, siX
es una referencia de valor izquierdo, entoncesstd::forward<x>(x)
producirá una referencia de valor izquierdo, mientras questatic_cast<x&&>(x)
producirá una referencia de valor derecho.Por lo tanto, es importante usar el mecanismo de reenvío correcto dependiendo del tipo de los argumentos que se están reenviando. Si los argumentos son referencias hacia adelante, tanto
std::forward
comostatic_cast
funcionarán, y producirán exactamente el mismo resultado.</x&&></x&&></x&&>