¿Todas / la mayoría de las funciones de setter en C++11 deben escribirse como plantillas de función que acepten referencias universales?
Considere una clase X
con variables miembro N
, cada uno de algunos tipos copiablesy móviles, y N
funciones de setter correspondientes.
En C++98, la definición de X
probablemente se vería algo como esto:
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 enlazar tanto a los argumentos lvalue como a rvalue. Dependiendo del argumento real, este podría resultar en la creación de un temporal y eventualmente resultará en una copia asignación; 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 setter reescribiéndolas 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 enlazar a const
/non-const
, volatile
/no-volatile
, y a cualquier tipo convertible en general, evitando la creación de temporarios y valores pasantes directamente a operator =
. No copiable, ahora se admiten los tipos movible. Las posibles vinculaciones no deseadas pueden eliminarse a través de static_assert
o a través de std::enable_if
.
Así que mi pregunta es: como una guía de diseño , ¿deberían todas (digamos, la mayoría) las funciones setter en C++11 ser escritas como plantillas de función que acepten referencias universales?
Aparte de la sintaxis más engorrosa y la imposibilidad de usar herramientas de ayuda similares a Intellisense al escribir código en esas funciones setter, ¿hay alguna desventaja relevante con el principio hipotético"escribir funciones setter como plantillas de función que acepten referencias universales siempre que sea posible"?
1 answers
Conoces las clases A y B, así que sabes si son móviles o no y si este diseño es necesario en última instancia. Para algo como std::string
, es una pérdida de tiempo cambiar el código existente a menos que sepa que tiene un problema de rendimiento aquí. Si estás tratando con auto_ptr
, entonces es hora de arrancarlo y usar unique_ptr
.
Normalmente se prefiere ahora tomar argumentos por valor si no sabe nada 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 excepto movilidad y ofrece una interfaz relativamente intuitiva.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-07 14:10:25