funciones - plantillas c++
¿Deberían escribirse todas las funciones/más setter en C++ 11 como plantillas de funciones que acepten referencias universales? (1)
Considere una clase X
con N
variables miembro, cada uno de algunos tipos copiable y móvil , y N
funciones setter correspondientes. En C ++ 98, la definición de X
probablemente se vería así:
class X
{
public:
void set_a(A const& a) { _a = a; }
void set_b(B const& b) { _b = b; }
...
private:
A _a;
B _b;
...
};
Las funciones Setter de la clase X
anterior pueden vincularse tanto a lvalue como a rvalue arguments. Dependiendo del argumento real, esto podría resultar en la creación de un temporal y eventualmente resultará en una asignación de copia; debido a esto, los tipos no copiables no son compatibles con este diseño.
Con C ++ 11 tenemos semántica de movimiento, reenvío perfecto y referencias universales (terminología de Scott Meyers), que permiten un uso más eficiente y generalizado de las funciones del colocador al reescribirlas de esta manera:
class X
{
public:
template<typename T>
void set_a(T&& a) { _a = std::forward<T>(a); }
template<typename T>
void set_b(T&& b) { _b = std::forward<T>(b); }
...
private:
A _a;
B _b;
...
};
Las referencias universales pueden vincularse a const
/ const
- const
, volatile
/ no volatile
, y a cualquier tipo convertible en general, evitando la creación de valores temporales y pasando valores directamente a operator =
. Los tipos movibles no copiables ahora son compatibles. Posiblemente los enlaces no deseados se pueden eliminar a través de static_assert
o mediante std::enable_if
.
Así que mi pregunta es: como una guía de diseño , ¿deberían escribirse todas las funciones de setter (por ejemplo, la mayoría) en C ++ 11 como plantillas de funciones que aceptan referencias universales?
Además de la sintaxis más engorrosa y la imposibilidad de utilizar herramientas de ayuda tipo Intellisense al escribir código en esas funciones de setter, ¿hay desventajas relevantes con el principio hipotético de " funciones de establecimiento de escritura como plantillas de función que aceptan referencias universales siempre que sea posible "?
Usted conoce las clases A y B, para saber si son móviles o no y si este diseño es finalmente necesario. Para algo como std::string
, es una pérdida de tiempo cambiar el código existente a menos que sepa que aquí tiene un problema de rendimiento. Si está tratando con auto_ptr
, entonces es hora de arrancarlo y usar unique_ptr
.
Por lo general, se prefiere ahora tomar argumentos por valor si no conoce algo más específico, como
void set_a(A a) { _a = std::move(a); }
Esto permite el uso de cualquiera de los constructores de A
sin requerir nada más que la movilidad y ofrece una interfaz relativamente intuitiva.