2011-02-02 12 views
6

me puede escribir una función con plantilla de esta maneraplantilla pasar por valor o referencia const o ...?

template<class T> void f(T x) {...} 

o esta forma

template<class T> void f(T const& x) {...} 

supongo que la segunda opción puede ser más óptimo, ya que evita explícitamente una copia, pero sospecho que puede también fallan para algunos tipos específicos T (por ejemplo, funtores?). Entonces, ¿cuándo debería usar la primera opción y cuándo usar la segunda? También hay este boost::call_traits<T>::param_type y boost::reference_wrapper que estaban en las respuestas a mi previous question, pero la gente no los usa en todas partes, ¿verdad? ¿Hay una regla general para esto? Gracias.

+1

A riesgo de parecer tonto, debo preguntar: ¿cómo podría fallar para un funtor? – Beta

+0

@Beta: fue una suposición aleatoria. Si alguien pudiera explicar en qué casos realmente puede fallar, estaría interesado. –

+0

¿Qué es lo que estás tratando de lograr? Depende del código interno en 'f'. –

Respuesta

11

¿Existe una regla de oro para esto?

Se aplican las mismas reglas generales sobre cuándo utilizar el paso por referencia que el valor por pasar.

Si espera que T sea siempre un tipo numérico o un tipo que sea muy barato de copiar, puede tomar el argumento por valor. Si de todos modos va a hacer una copia del argumento en una variable local en la función, debe tomarlo por valor a help the compiler elide copies that don't really need to be made.

De lo contrario, tome el argumento por referencia. En el caso de los tipos que son baratos de copiar, puede ser más costoso, pero para otros tipos será más rápido. Si encuentra que este es un punto de acceso de rendimiento, puede sobrecargar la función para diferentes tipos de argumentos y hacer lo correcto para cada uno de ellos.

+0

¿Entonces no hay ningún problema específico de la plantilla? –

+1

@ 7vies: No realmente; El único "problema" es que, en lugar de tener solo un tipo en el que pensar, debe decidir qué tiene sentido para el grupo de tipos con el que se usará la plantilla. –

+0

@James McNellis: Supongo que a veces no se puede decidir esto, como por ejemplo que STL aceptaría funtores por valor, mientras que uno podría tener un functor "en gran estado" y eso sería ineficiente. ¿Debería uno usar ese 'boost :: call_traits :: param_type' en este caso, o apegarse a simplemente pasar por valor como lo hizo STL? –

0

Además de lo escrito por James McNellis, sólo quiero añadir que se puede especializar su plantilla para este tipo de referencia (for example like this)

0

boost::traits tiene un rasgo tipo que selecciona el "mejor" tipo, basado en T:

call_traits<T>::param_type

Como ya se ha mencionado, no hay problemas específicos de la plantilla.

+0

normalmente el compilador no puede deducir un argumento de ejemplo en este caso (es un problema específico de la plantilla). – user396672

6

sospecho que también puede fallar para algunos tipos específicos

paso por referencia a const es el único mecanismo de paso que "nunca" falla. No plantea ningún requisito en T, acepta valores lvalues ​​y r como argumentos y permite conversiones implícitas.

1

No has de despertar a los muertos, pero la cabeza de un problema similar y aquí es un código de ejemplo que muestra cómo utilizar C++ rasgos de tipo 11s para deducir si un parámetro se debe pasar por valor o referencia:

#include <iostream> 
#include <type_traits> 

template<typename key_type> 
class example 
{ 
    using parameter_type = typename std::conditional<std::is_fundamental<key_type>::value, key_type, key_type&>::type; 

public: 
    void function(parameter_type param) 
    { 
     if (std::is_reference<parameter_type>::value) 
     { 
      std::cout << "passed by reference" << std::endl; 
     } else { 
      std::cout << "passed by value" << std::endl; 
     } 
    } 
}; 

struct non_fundamental_type 
{ 
    int one; 
    char * two; 
}; 

int main() 
{ 
    int one = 1; 
    non_fundamental_type nft; 

    example<int>().function(one); 
    example<non_fundamental_type>().function(nft); 

    return 0; 
} 

Espero que ayude a otros con un problema similar.

Cuestiones relacionadas