Quiero sobrecargar una función para que manipule su argumento de alguna manera y luego devuelve una referencia al argumento, pero si el argumento no es mutable, entonces debe devolver una copia manipulada del argumento en lugar. Después de perder el tiempo por años, esto es lo que he pensado.Sobrecarga de la función rvalue
using namespace std;
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string &&in)
{
return move(foo(in));
}
string foo(const string& in)
{
return foo(string(in));
}
Este código parece funcionar correctamente, pero estoy interesado en saber si alguien puede pensar en una mejor manera de hacerlo.
Aquí es un programa de prueba:
int main(void)
{
string var = "world";
const string var2 = "const world";
cout << foo(var) << endl;
cout << var << endl;
cout << foo(var2) << endl;
cout << var2 << endl;
cout << foo(var + " and " + var2) << endl;
return 0;
}
La salida correcta es
hello world
hello world
hello const world
const world
hello hello world and const world
Calculo que sería un poco más ordenado si podía hacer esto:
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string in)
{
return move(foo(in));
}
Por supuesto, eso no funciona porque la mayoría de las llamadas a funciones en foo
serían ambiguas, incluida la llamada en foo
sí mismo! Pero si de alguna manera pudiera decirle al compilador que priorice el primero ...
Como dije, el código que publiqué funciona correctamente. Lo principal que no me gusta de él es el código adicional repetitivo. Si tuviera un montón de funciones así, se convertiría en un desastre, y la mayoría serían muy repetitivas. Entonces, como segunda parte de mi pregunta: ¿alguien puede pensar en una forma de generar automáticamente el código para la segunda y tercera función foo
? por ejemplo,
// implementation of magic_function_overload_generator
// ???
string& foo(string &in);
magic_function_overload_generator<foo>;
string& bar(string &in);
magic_function_overload_generator<bar>;
// etc
Esto suena aterrador. Dependiendo de qué tipo pase a la función, el estado resultante del valor de retorno * y el parámetro * podría ser completamente diferente. Eso es solo pedir errores sutiles. ¿Por qué no dejar que el usuario decida si quiere modificar el objeto en su lugar o devolver una copia llamando explícitamente a diferentes funciones? – jalf
No me parece particularmente aterrador, pero quizás tengas razón. La forma en que pienso es que la función cambia la entrada siempre que sea capaz; pero si no puede ... no es así, pero todavía da el valor de retorno correcto. El tipo de cosas que podría usar es algo así como una función "Puntuar", que toma una cadena mal puntuada y la corrige. Es posible que desee enviar el resultado directamente a cout, o quizás desee realizar algunas otras operaciones en la cadena después. Entonces, a veces puedes pasar valores constantes, y algunas veces ... bueno, entiendes la idea. – karadoc
pero mi punto es que si uno o el otro pasa no depende de lo que el programador quiere, sino de algunos detalles semánticos relativamente sutiles (¿el tipo de argumento es const o no? ¿Es un valor r o no?), que podría cambiar fácilmente con el tiempo sin que el programador tome la decisión explícita de que "ahora quiero devolver una copia, en lugar de modificar el objeto en su lugar". Entiendo lo que intenta hacer, pero es una decisión que el programador puede tomar fácilmente, y que hacer que su biblioteca adivine erróneamente puede tener consecuencias potencialmente muy malas. – jalf