c++ - todas - tipos de funciones en lenguaje c
Sobrecargar una funciĆ³n de C++ de acuerdo con el valor de retorno (17)
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.
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);
Deje que mul sea una clase, mul (x, y) su constructor y sobrecargue algunos operadores de conversión.
Hmmm, el siguiente artículo de proyecto de código parece hacer lo que buscas. Debe ser mágico;)
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".
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.
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.
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;
}
};
usar como
double d = mul(1,2);
long l = mul(1,2);
no es estúpido <>
Podrías hacer algo como
template<typename T>
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<int>(2,3);
std::string s = mul<std::string>(2,3);
No hay forma de sobrecargar el valor de retorno.
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 alcance diferente (de ahí el operador :: resolución de alcance).
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.
Por lo que sé, no puedes (gran pena, sin embargo ...). Como solución alternativa, puede definir un parámetro ''out'' y sobrecargarlo.
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.
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<int> x;
x.push_back(3);
x.push_back(4);
x.push_back(5);
x.push_back(6);
vector<int> intDest(x.size());
transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 15 20 25 30
for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
cout << *i << " ";
cout << endl;
vector<string> stringDest(x.size());
transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 555 5555 55555 555555
for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
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.
Tienes que decirle al compilador 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<char>(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 compilador 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 compilará si se crea una instancia:
template<typename T>
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 compilará, lo cual es bueno porque solo queremos usar algunas funciones limitadas a través de la especialización de plantillas:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
Por lo tanto, se compilará el siguiente código:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
Pero este no:
short n2 = mul<short>(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<typename T>
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>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
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<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
Y este código se usaría como tal:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(''6'', 3); // s = "666"
Y la siguiente línea:
short n2 = mul<short>(6, 3); // n = 18
Todavía no compilaría.
Conclusión
Me encanta C ++ ...
:-pag
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.
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.