C ++ 0x muestra un ejemplo de uso std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
¿Cuándo es ventajoso usar std::forward
, siempre?
Además, requiere su uso &&
en la declaración de parámetros, ¿es válido en todos los casos? Pensé que tenía que pasar temporarios a una función si la función se declaraba con &&
ella, por lo que ¿se puede llamar a foo con algún parámetro?
Por último, si tengo una llamada de función como esta:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Debería usar esto en su lugar:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
Además, si usa los parámetros dos veces en la función, es decir, reenvío a dos funciones al mismo tiempo, ¿es conveniente usarlo std::forward
? ¿No std::forward
convertirá lo mismo en temporal dos veces, moviendo la memoria y haciendo que no sea válida para un segundo uso? ¿Estaría bien el siguiente código?
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Estoy un poco confundido std::forward
y con mucho gusto usaría algo de limpieza.
fuente
Args...&& args
?La respuesta de Kerrek es muy útil, pero no responde completamente la pregunta del título:
Para responderlo, primero debemos introducir una noción de referencias universales . Scott Meyers dio este nombre y hoy en día a menudo se les llama referencias de reenvío. Básicamente, cuando ves algo como esto:
tenga en cuenta que
param
no se trata de una referencia de valor (como se puede tentar a concluir), sino de una referencia universal *. Las referencias universales se caracterizan por una forma muy restringida (soloT&&
, sin const o calificadores similares) y por deducción de tipo : el tipoT
se deducirá cuandof
se invoque. En pocas palabras, las referencias universales corresponden a las referencias de valor si se inicializan con valores, y a las referencias de valor si se inicializan con valores.Ahora es relativamente fácil responder la pregunta original: solicítela
std::forward
a:Un ejemplo para el primer caso:
En el código anterior, no queremos
prop
tener algún valor desconocido después de queother.set(..)
haya terminado, por lo que no se realiza ningún reenvío aquí. Sin embargo, cuandobar
llamamos hacia adelante,prop
ya que hemos terminado con él ybar
podemos hacer lo que quiera con él (por ejemplo, moverlo).Un ejemplo para el segundo caso:
Esta plantilla de función debe moverse
prop
al valor de retorno si es un valor r y copiarlo si es un valor l. En caso de que omitimosstd::forward
al final, siempre creamos una copia, que es más costosa cuandoprop
resulta ser un valor.* para ser completamente preciso, una referencia universal es un concepto de tomar una referencia rvalue a un parámetro de plantilla no calificado cv.
fuente
¿Ayuda este ejemplo? Luché por encontrar un ejemplo no genérico útil de std :: forward, pero me topé con un ejemplo de una cuenta bancaria en la que pasamos el efectivo para ser depositado como argumento.
Entonces, si tenemos una versión constante de una cuenta, deberíamos esperar cuando la pasamos a nuestra plantilla de depósito <> que se llama a la función constante; y esto arroja una excepción (¡la idea es que se trataba de una cuenta bloqueada!)
Si tenemos una cuenta no constante, entonces deberíamos poder modificar la cuenta.
Para construir:
Rendimiento esperado:
fuente