Question

Nous savons tous que vous pouvez surcharger une fonction en fonction des paramètres:

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

Pouvez-vous surcharger une fonction en fonction de la valeur de retour? Définissez une fonction qui renvoie différentes choses en fonction de l'utilisation de la valeur renvoyée:

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)

Vous pouvez supposer que le premier paramètre est compris entre 0 et 9, vous n'avez pas besoin de vérifier l'entrée ni de gérer les erreurs.

Était-ce utile?

La solution

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

Ce n'est pas que j'utiliserais cela.

Autres conseils

Vous devez indiquer au compilateur quelle version utiliser. En C ++, vous pouvez le faire de trois manières.

Différenciez explicitement les appels en tapant

Vous avez quelque peu triché parce que vous avez envoyé un entier à une fonction en attente d'un caractère et que vous avez envoyé à tort le nombre six lorsque la valeur du caractère '6' n'est pas 6 mais 54 (en ASCII):

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

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

La bonne solution serait, bien sûr,

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

Cela méritait d’être mentionné, même si vous ne souhaitiez pas la solution.

Différenciez explicitement les appels par un pointeur factice

Vous pouvez ajouter un paramètre factice à chaque fonction, forçant ainsi le compilateur à choisir les bonnes fonctions. Le moyen le plus simple consiste à envoyer un pointeur factice NULL du type souhaité pour le retour:

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

Qui peut être utilisé avec le code:

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

Différenciez explicitement les appels en modélisant la valeur de retour

Avec cette solution, nous créons un " mannequin & "; fonctionne avec du code qui ne compilera pas s'il est instancié:

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

Vous remarquerez que cette fonction ne compilera pas, ce qui est une bonne chose car nous souhaitons uniquement utiliser certaines fonctions limitées par le biais de la spécialisation de modèles:

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

Ainsi, le code suivant sera compilé:

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

Mais celui-ci ne le fera pas:

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

Différenciez explicitement les appels en modélisant la valeur de retour, 2

  
    

Hé, vous avez triché aussi!

  

D'accord, j'ai utilisé les mêmes paramètres pour les deux & "; surchargés &"; les fonctions. Mais vous avez commencé à tricher (voir ci-dessus) ...

^ _ ^

Plus sérieusement, si vous avez besoin de paramètres différents, vous devrez écrire plus de code, puis utiliser explicitement les bons types lors de l'appel des fonctions pour éviter les ambiguïtés:

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

Et ce code serait utilisé comme tel:

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

Et la ligne suivante:

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

Ne compilerait toujours pas.

Conclusion

J'aime le C ++ ...

: - p

Si vous voulez que mul soit une vraie fonction au lieu d'une classe, vous pouvez simplement utiliser une classe intermédiaire:

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

Cela vous permet, par exemple, de passer <=> une fonction à des algorithmes 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;
}

Non.

Vous ne pouvez pas surcharger par la valeur renvoyée car l'appelant peut tout faire (ou rien) avec. Considérez:

mul(1, 2);

La valeur de retour est simplement supprimée. Il est donc impossible de choisir une surcharge basée uniquement sur la valeur de retour.

Utilisez la conversion implicite dans une classe intermédiaire.

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

BadIdea mul(int, int)

Vous avez l’idée, idée terrible cependant.

Soit mul une classe, mul (x, y) son constructeur et surcharge certains opérateurs de casting.

Vous ne pouvez pas surcharger une fonction en fonction de la valeur de retour uniquement.

Toutefois, bien qu’il ne s’agisse pas d’une fonction surchargée, vous pouvez renvoyer de votre fonction l’instance d’une classe surchargeant les opérateurs de conversion.

Je suppose que vous pourriez le renvoyer avec un type étrange Foo qui capture simplement les paramètres, puis Foo a un opérateur implicite int et une chaîne d'opérateur, et il & "fonctionnera &"; t vraiment être surchargé, plutôt un truc de conversion implicite.

Hmmm, le article de projet de code semble faire ce que vous êtes après. Doit être magique;)

Bref et simple, la réponse est NON. En C ++, les exigences sont les suivantes:

1: le nom des fonctions DOIT être le même

2: les arguments DOIVENT être différents
* Le type de retour peut être identique ou différent

//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);

Autant que je sache, vous ne pouvez pas (grande pitié, cependant ...). Pour contourner le problème, vous pouvez définir un paramètre "out" et le surcharger.

Pas en C ++. Dans l'exemple ci-dessus, vous obtiendrez la valeur renvoyée qui est une conversion dans quelque chose que string peut comprendre, très probablement un char. Ce qui serait ASCII 18 ou & "; Contrôle de périphérique 2 &";

Vous pouvez utiliser la solution de foncteur ci-dessus. C ++ ne supporte pas cela pour les fonctions sauf pour const. Vous pouvez surcharger basé sur const.

Vous pouvez utiliser un modèle, mais vous devez ensuite spécifier le paramètre de modèle lorsque vous effectuez l'appel.

Mettez-le dans un espace de noms différent? Ce serait comme ça que je le ferais. Pas strictement une surcharge, mais plutôt deux méthodes portant le même nom, mais une portée différente (d’où l’opérateur :: scope resolution).

Donc stringnamespace :: mul et intnamespace :: mul. Ce n’est peut-être pas ce que vous demandez, mais cela semble être le seul moyen de le faire.

Vous pouvez faire quelque chose comme

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

Et appelez ça comme ça:

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

Il n'y a aucun moyen de surcharger la valeur de retour.

OK, vos génies;) voici comment vous le faites comme un pro.


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

utiliser comme


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

pas stupide < >

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top