Sobrecargar una función de C ++ de acuerdo con el valor de retorno

Todos sabemos que puede sobrecargar una función de acuerdo con los parámetros:

int mul(int i, int j) { return i*j; } std::string mul(char c, int n) { return std::string(n, c); } 

¿Se puede sobrecargar una función de acuerdo con el valor de retorno? Defina una función que devuelve diferentes cosas según cómo se usa el valor de retorno:

 int n = mul(6, 3); // n = 18 std::string s = mul(6, 3); // s = "666" // Note that both invocations take the exact same parameters (same types) 

Puede suponer que el primer parámetro está entre 0-9, no es necesario verificar la entrada o tiene algún tipo de manejo de error.

 class mul { public: mul(int p1, int p2) { param1 = p1; param2 = p2; } operator int () { return param1 * param2; } operator std::string () { return std::string(param2, param1 + '0'); } private: int param1; int param2; }; 

No es que yo use eso.

Tienes que decirle al comstackdor qué versión usar. En C ++, puedes hacerlo de tres maneras.

Explique explícitamente las llamadas escribiendo

Te engañaste un tanto porque enviaste un número entero a una función esperando un char, y envió erróneamente el número seis cuando el valor de char de ‘6’ no es 6 sino 54 (en ASCII):

 std::string mul(char c, int n) { return std::string(n, c); } std::string s = mul(6, 3); // s = "666" 

La solución correcta sería, por supuesto,

 std::string s = mul(static_cast(54), 3); // s = "666" 

Merece la pena mencionar esto, supongo, incluso si no quieres la solución.

Diferenciar explícitamente las llamadas por puntero ficticio

Puede agregar un parámetro ficticio a cada función, lo que obliga al comstackdor a elegir las funciones correctas. La forma más fácil es enviar un puntero ficticio NULL del tipo deseado para la devolución:

 int mul(int *, int i, int j) { return i*j; } std::string mul(std::string *, char c, int n) { return std::string(n, c); } 

Que se puede usar con el código:

 int n = mul((int *) NULL, 6, 3); // n = 18 std::string s = mul((std::string *) NULL, 54, 3); // s = "666" 

Diferenciar explícitamente las llamadas mediante plantillas del valor de retorno

Con esta solución, creamos una función “ficticia” con código que no se comstackrá si se crea una instancia:

 template T mul(int i, int j) { // If you get a compile error, it's because you did not use // one of the authorized template specializations const int k = 25 ; k = 36 ; } 

Notará que esta función no se comstackrá, lo cual es bueno porque solo queremos usar algunas funciones limitadas a través de la especialización de plantillas:

 template<> int mul(int i, int j) { return i * j ; } template<> std::string mul(int i, int j) { return std::string(j, static_cast(i)) ; } 

Por lo tanto, se comstackrá el siguiente código:

 int n = mul(6, 3); // n = 18 std::string s = mul(54, 3); // s = "666" 

Pero este no:

 short n2 = mul(6, 3); // error: assignment of read-only variable 'k' 

Explique explícitamente las llamadas mediante la plantilla del valor de retorno, 2

¡Oye, también hiciste trampa!

Correcto, utilicé los mismos parámetros para las dos funciones “sobrecargadas”. Pero comenzaste a hacer trampa (ver arriba) …

^ _ ^

Más en serio, si necesita tener parámetros diferentes, deberá escribir más código y luego usar explícitamente los tipos correctos cuando llame a las funciones para evitar ambigüedades:

 // For "int, int" calls template T mul(int i, int j) { // If you get a compile error, it's because you did not use // one of the authorized template specializations const int k = 25 ; k = 36 ; } template<> int mul(int i, int j) { return i * j ; } // For "char, int" calls template T mul(char i, int j) { // If you get a compile error, it's because you did not use // one of the authorized template specializations const int k = 25 ; k = 36 ; } template<> std::string mul(char i, int j) { return std::string(j, (char) i) ; } 

Y este código se usaría como tal:

 int n = mul(6, 3); // n = 18 std::string s = mul('6', 3); // s = "666" 

Y la siguiente línea:

 short n2 = mul(6, 3); // n = 18 

Todavía no comstackría.

Conclusión

Me encanta C ++ …

:-pag

Si quisieras que mul fuera una función real en lugar de una clase, podrías usar una clase intermedia:

 class StringOrInt { public: StringOrInt(int p1, int p2) { param1 = p1; param2 = p2; } operator int () { return param1 * param2; } operator std::string () { return std::string(param2, param1 + '0'); } private: int param1; int param2; }; StringOrInt mul(int p1, int p2) { return StringOrInt(p1, p2); } 

Esto le permite hacer cosas como pasar mul como una función a algoritmos std:

 int main(int argc, char* argv[]) { vector x; x.push_back(3); x.push_back(4); x.push_back(5); x.push_back(6); vector intDest(x.size()); transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5)); // print 15 20 25 30 for (vector::const_iterator i = intDest.begin(); i != intDest.end(); ++i) cout << *i << " "; cout << endl; vector stringDest(x.size()); transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5)); // print 555 5555 55555 555555 for (vector::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i) cout << *i << " "; cout << endl; return 0; } 

No.

No puede sobrecargar por valor devuelto porque la persona que llama puede hacer cualquier cosa (o nada) con ella. Considerar:

mul(1, 2);

El valor de retorno simplemente se descarta, por lo que no hay forma de que pueda elegir una sobrecarga basándose solo en el valor de retorno.

Use la conversión implícita en una clase intermedia.

 class BadIdea { public: operator string() { return "silly"; } operator int() { return 15; } }; BadIdea mul(int, int) 

Aunque tienes la idea, idea terrible.

Deje que mul sea una clase, mul (x, y) su constructor y sobrecargue algunos operadores de conversión.

No puede sobrecargar una función basándose solo en el valor de retorno.

Sin embargo, aunque estrictamente hablando, esta no es una función sobrecargada, puede regresar de su función como resultado de una instancia de una clase que sobrecarga a los operadores de conversión.

Supongo que podría hacer que devuelva algún tipo extraño de Foo que solo capture los parámetros y luego Foo tenga un operador implícito int y una cadena de operador, y “funcionaría”, aunque no sería una sobrecarga, sino un truco de conversión implícito.

Hmmm, el siguiente artículo de proyecto de código parece hacer lo que buscas. Debe ser mágico;)

Corto y simple, la respuesta es NO. En C ++ los requisitos son:

1: el nombre de las funciones DEBE ser el mismo
2: conjunto de argumentos DEBE diferir
* El tipo de devolución puede ser el mismo o diferente

 //This is not valid int foo(); float foo(); typedef int Int; int foo(int j); int foo(Int j); //Valid: int foo(int j); char* foo(char * s); int foo(int j, int k); float foo(int j, float k); float foo(float j, float k); 

Por lo que sé, no puedes (gran pena, sin embargo …). Como solución alternativa, puede definir un parámetro ‘out’ y sobrecargarlo.

No en C ++. Lo que obtendrías en el ejemplo anterior sería el valor devuelto, que es un int vertido en algo que la string puede entender, muy probablemente un char . Que sería ASCII 18 o “dispositivo de control 2”.

Puede usar la solución de functor anterior. C ++ no es compatible con esto para funciones a excepción de const. Puede sobrecargar según const.

Puede usar una plantilla, pero luego debe especificar el parámetro de la plantilla cuando realiza la llamada.

Ponlo en un espacio de nombres diferente? Así sería como lo haría. No es estrictamente una sobrecarga, sino simplemente tener dos métodos con el mismo nombre, pero con un scope diferente (de ahí el operador :: resolución de scope).

Así que stringnamespace :: mul y intnamespace :: mul. Quizás no es realmente lo que estás preguntando, pero parece ser la única forma de hacerlo.

Podrías hacer algo como

 template T mul(int i,int j){ return i * j; } template<> std::string mul(int i,int j){ return std::string(j,i); } 

Y luego llámalo así:

 int x = mul(2,3); std::string s = mul(2,3); 

No hay forma de sobrecargar el valor de retorno.

OK genios;) así es como lo haces como un profesional.

 class mul { int m_i,m_j; public: mull(int i,int j):m_i(i),m_j(j){} template operator R() { return (R)m_i * m_j; } };
class mul { int m_i,m_j; public: mull(int i,int j):m_i(i),m_j(j){} template operator R() { return (R)m_i * m_j; } }; 

usar como

 double d = mul(1,2); long l = mul(1,2); 

no es estúpido <>