Überladen Sie eine C++-Funktion entsprechend dem Rückgabewert

Lesezeit: 7 Minuten

Uberladen Sie eine C Funktion entsprechend dem Ruckgabewert
Motti

Wir alle wissen, dass Sie eine Funktion gemäß den Parametern überladen können:

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

Kann man eine Funktion entsprechend dem Rückgabewert überladen? Definieren Sie eine Funktion, die je nach Verwendung des Rückgabewerts unterschiedliche Dinge zurückgibt:

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)

Sie können davon ausgehen, dass der erste Parameter zwischen 0 und 9 liegt, Sie müssen die Eingabe nicht überprüfen oder eine Fehlerbehandlung durchführen.

  • Hmm, folgendes Code-Projekt-Artikel scheint zu tun, was Sie wollen. Muss magisch sein 😉

    – SmacL

    22. Oktober 2008 um 15:13 Uhr

  • Ich wünschte, es wäre möglich. Ich bin auf ein paar Fälle gestoßen, in denen ich es hätte verwenden können, um den Code zu vereinfachen …

    – Brian Knoblauch

    22. Oktober 2008 um 15:15 Uhr

  • @Brian – der Effekt ist möglich. Siehe die Antworten unten.

    – Aaron

    22. Oktober 2008 um 17:21 Uhr

  • Aber nur weil du es kannst, heißt das nicht, dass du es solltest. 🙂 Schön, jemandem das Leben schwer zu machen…

    – Gishu

    23. Oktober 2008 um 8:25 Uhr

  • Hier findet nur eine implizite Konvertierung statt, keine Überladung

    – jaraaj

    23. Oktober 2008 um 8:46 Uhr

Uberladen Sie eine C Funktion entsprechend dem Ruckgabewert
paercebal

Sie müssen dem Compiler mitteilen, welche Version verwendet werden soll. In C++ können Sie dies auf drei Arten tun.

Unterscheiden Sie die Aufrufe explizit durch Typisierung

Sie haben etwas geschummelt, weil Sie eine Ganzzahl an eine Funktion gesendet haben, die auf ein Zeichen wartet, und fälschlicherweise die Zahl sechs gesendet haben, wenn der Zeichenwert von ‘6’ nicht 6, sondern 54 (in ASCII) ist:

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

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

Die richtige Lösung wäre natürlich

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

Das war erwähnenswert, denke ich, auch wenn Sie die Lösung nicht wollten.

Unterscheiden Sie die Aufrufe explizit durch Dummy-Zeiger

Sie können jeder Funktion einen Dummy-Parameter hinzufügen, wodurch der Compiler gezwungen wird, die richtigen Funktionen auszuwählen. Am einfachsten ist es, einen NULL-Dummy-Zeiger des gewünschten Typs für die Rückgabe zu senden:

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

Was mit dem Code verwendet werden kann:

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

Unterscheiden Sie die Aufrufe explizit, indem Sie den Rückgabewert mit Vorlagen versehen

Mit dieser Lösung erstellen wir eine „Dummy“-Funktion mit Code, der nicht kompiliert wird, wenn er instanziiert wird:

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

Sie werden feststellen, dass diese Funktion nicht kompiliert wird, was gut ist, da wir nur einige eingeschränkte Funktionen durch die Vorlagenspezialisierung verwenden möchten:

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

Daher wird der folgende Code kompiliert:

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

Aber dieses wird nicht:

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

Die Aufrufe explizit differenzieren, indem der Rückgabewert mit Templates versehen wird, 2

Hey, du hast auch geschummelt!

Richtig, ich habe die gleichen Parameter für die beiden “überladenen” Funktionen verwendet. Aber Sie haben mit dem Schummeln angefangen (siehe oben) …

^_^

Im Ernst, wenn Sie andere Parameter benötigen, müssen Sie mehr Code schreiben und dann beim Aufrufen der Funktionen explizit die richtigen Typen verwenden, um Mehrdeutigkeiten zu vermeiden:

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

Und dieser Code würde als solcher verwendet werden:

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

Und die folgende Zeile:

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

Würde immer noch nicht kompilieren.

Fazit

Ich liebe C++…

😛

  • Ich bin zerrissen. Auf der positiven Seite ist es clever und auf den Punkt gebracht. Auf der Minusseite ist es eine geladene Waffe.

    – jrodman

    26. März 2015 um 10:47 Uhr

  • @jrodman: Könnten Sie bitte die “geladene Waffe” mit technischem Input näher erläutern? Ich sehe nicht, wie alles, was ich in dieser Antwort geschrieben habe (Dummy-Zeiger oder Rückgabewert mit Vorlage), geht gegen die Sprache.

    – Paercebal

    1. April 2015 um 10:19 Uhr

  • @jrodman: C ++ ist eine geladene Waffe für sich. Deshalb lieben wir es so sehr 🙂

    – Rostiges Pferd

    17. Juni 2016 um 11:11 Uhr

1646686211 142 Uberladen Sie eine C Funktion entsprechend dem Ruckgabewert
Münze

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

Nicht, dass ich das verwenden würde.

  • Sie können Konvertierungsfunktionen wie hinzufügen operator identity<int(*)()>::type() { return &operator int; }wodurch es an eine Funktion übergeben werden kann, die a nimmt int(*)()und wenn der Funktionszeiger aufgerufen wird, die operator int Funktion aufgerufen wird.

    – Johannes Schaub – litb

    18. Dezember 2009 um 11:29 Uhr

Wenn du machen wolltest mul eine echte Funktion anstelle einer Klasse sein, könnten Sie einfach eine Zwischenklasse verwenden:

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

Auf diese Weise können Sie Dinge wie das Passen tun mul als Funktion in Standardalgorithmen:

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

Nein.

Sie können nicht mit dem Rückgabewert überladen, da der Aufrufer alles (oder nichts) damit machen kann. Erwägen:

mul(1, 2);

Der Rückgabewert wird einfach verworfen, sodass es keine Möglichkeit gibt, eine Überladung allein auf der Grundlage des Rückgabewerts auszuwählen.

Verwenden Sie die implizite Konvertierung in einer Zwischenklasse.

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

BadIdea mul(int, int)

Du verstehst die Idee, aber eine schreckliche Idee.

1646686212 907 Uberladen Sie eine C Funktion entsprechend dem Ruckgabewert
Federico A. Ramponi

Sei mul eine Klasse, mul(x, y) ihr Konstruktor und überlade einige Casting-Operatoren.

Uberladen Sie eine C Funktion entsprechend dem Ruckgabewert
Franz Penow

Sie können eine Funktion nicht nur basierend auf dem Rückgabewert überladen.

Obwohl dies streng genommen keine überladene Funktion ist, könnten Sie als Ergebnis Ihrer Funktion eine Instanz einer Klasse zurückgeben, die die Konvertierungsoperatoren überlädt.

969310cookie-checkÜberladen Sie eine C++-Funktion entsprechend dem Rückgabewert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy