Pregunta

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 devuelva cosas diferentes según cómo se use 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 tener algún manejo de errores.

¿Fue útil?

Solución

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 usaría eso.

Otros consejos

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

Diferenciar explícitamente las llamadas escribiendo

Hiciste trampa de alguna manera porque enviaste un número entero a una función esperando un carácter, y enviaste erróneamente el número seis cuando el valor de carácter 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"

Vale la pena mencionar esto, supongo, incluso si no desea 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 la plantilla del valor de retorno

Con esta solución, creamos un " dummy " funciona con código que no se compilará si se 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ás 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 plantilla:

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’

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

  
    

¡Oye, tú también hiciste trampa!

  

Correcto, utilicé los mismos parámetros para los dos " sobrecargado " funciones Pero comenzaste a hacer trampa (ver arriba) ...

^ _ ^

Más en serio, si necesita tener diferentes parámetros, deberá escribir más código y luego usar explícitamente los tipos correctos al llamar 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 se compilaría.

Conclusión

Me encanta C ++ ...

:-p

Si desea hacer que mul sea una función real en lugar de una clase, puede 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 <=> como una función a algoritmos estándar:

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;
}

No.

No puede sobrecargar por valor de retorno porque la persona que llama puede hacer cualquier cosa (o nada) con él. Considere:

mul(1, 2);

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

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

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

BadIdea mul(int, int)

Tienes la idea, terrible idea sin embargo.

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 únicamente en el valor de retorno.

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

Supongo que podría devolver un tipo extraño de Foo que simplemente captura los parámetros y luego Foo tiene un operador implícito int y una cadena de operador, y funcionaría & "; funcionaría &"; aunque no lo haría ' Realmente se está sobrecargando, más bien un truco de conversión implícito.

Hmmm, el siguiente artículo del proyecto de código parece hacer lo que eres después. 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: el conjunto de argumentos DEBE diferir
* El tipo de retorno 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);

Hasta donde yo sé, no puedes (aunque es una pena ...). Como solución alternativa, puede definir un parámetro 'out' y sobrecargarlo.

No en C ++. Lo que obtendría en el ejemplo anterior sería el valor devuelto, que es una conversión int en algo que string puede entender, muy probablemente un char. Que sería ASCII 18 o & Quot; control de dispositivo 2 & Quot ;.

Puede usar la solución de functor anterior. C ++ no admite esto para funciones, excepto para const. Puede sobrecargar en función de const.

Podría usar una plantilla, pero luego tendría que especificar el parámetro de la plantilla cuando realice la llamada.

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

Entonces stringnamespace :: mul e intnamespace :: mul. Tal vez no sea realmente lo que está preguntando, pero parece ser la única forma de hacerlo.

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.

OK, genios;) así es como lo hacen 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 estúpido < >

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top