Kann man mehrere Rechnungen in eine Funktion schreiben ?
-
Beschreibe einmal was du konkret vorhast. Dann kann man dir den besten helfen.
-
Du hast nur einen Rückgabewert.
Du kannst allerdings Paramter als Refernz (oder Zeiger) definieren. So kannst du noch weitere Werte zurück geben.
Als Beispiel die Standardfunktion
modf: http://www.cplusplus.com/reference/cmath/modf/
-
@Dirk: Sowas ist C-Style. In C++ wuerde man dafuer eine Datenstruktur definieren die man dann zurueckgibt.
modfwurde ja aus C uebernommen; Siehe lieberstd::div.
-
Versuch bitte, Fachbegriffe korrekt zu benutzen. Du willst ein Ergebnis nicht an einen "Typ" zurück geben. Ein Typ ist eine Kategorie von Objekten, kein Objekt selbst. So wie "Politiker" sich zu "Angela Merkel" (der Person, nicht dem Namen*) verhält.
Du beschreibst so etwas wie:
void diff_and_sum_with_references(int i, int j, int &diff, int &sum) { diff = i - j; sum = i + j; } std::tuple<int, int> diff_and_sum_with_tuples(int i, int j) { return std::make_tuple(i - j, i + j); } int main() { int i = 4, j =7; int diff, sum; diff_and_sum_with_references(i, j, diff, sum); // oder std::tie(diff, sum) = diff_and_sum_with_tuples(i, j); }*: Wenn du verstehst, warum dieser Zusatz notwendig war, dann bist du auf einem guten Weg, die Begriffe richtig zu verstehen.
-
Hey das ist jetzt vielleicht etwas spät aber wenn du in einer Funktion
mehrere Werte zurück geben willst könntest du auch Pointer benutzen das
ist vielleicht einfacher.int result, second_result; int *p_result = &result; int *p_second_result = &second_result; void calc_function(int *result, int second_result) { *result = 3+4; *second_result = 6*2; }
-
MNowo schrieb:
Hey das ist jetzt vielleicht etwas spät aber wenn du in einer Funktion
mehrere Werte zurück geben willst könntest du auch Pointer benutzen das
ist vielleicht einfacher.int result, second_result; int *p_result = &result; int *p_second_result = &second_result; void calc_function(int *result, int second_result) { *result = 3+4; *second_result = 6*2; }Kann man schon, macht man aber nicht.
-
Oh wieso nicht?

-
MNowo schrieb:
Oh wieso nicht?

Weil Pointer. Keiner mag Pointer.
-
Öhm okay...
-
MNowo schrieb:
[...] wenn du in einer Funktion mehrere Werte zurück geben willst könntest du auch Pointer benutzen das ist vielleicht einfacher.
/*...*/Mit Pointern ist es einfacher als mit Referenzen!? Erzähl mal ...
-
Also ich würds so machen:
std::vector<int> funktion(std::vector<int> const &x) { std::vector<int> y(3); y[0] = x[0] + x[1]; y[1] = 2*x[1] y[2] = x[0]/x[1]; return y; }Das wäre zum Beispiel eine Funktion vom R^2 -> R^3, also zwei Inputs und drei Outputs. Alternativ halt direkt mit Iteratoren.
-
MNowo schrieb:
Öhm okay...
Darüber hinaus hat der Pointeransatz (neben der umständlicheren Syntax*) den Nachteil, dass man auch nullptr übergeben kann und somit dereferenzieren nicht definiert ist.
Wenn man eine Signatur mit (nicht const) Pointern oder Referenzen sieht, hat das zwei unterschiedliche Bedeutungen:
-Referenz: Ein Outputparamater.
-Pointer: Ein optionaler Outputparamter.
Das ist dann wieder der Fall, dass guter Code sich selbst dokumentiert.*Manche sehen das auch als Vorteil, weil man so leichter erkennen kann, ob Elemente in der Funktion verändert werden, imo sollte man sich aber eh die Funktionssignatur anschauen und da siehts man auch.
-
Achso ja Referenzen sind natürlich noch einfacher aber die benutze ich nicht oft
drum sind mir die Pointer spontan eingefallen
-
happystudent schrieb:
Also ich würds so machen:
std::vector<int> funktion(std::vector<int> const &x) { std::vector<int> y(3); y[0] = x[0] + x[1]; y[1] = 2*x[1] y[2] = x[0]/x[1]; return y; }Das wäre zum Beispiel eine Funktion vom R^2 -> R^3, also zwei Inputs und drei Outputs. Alternativ halt direkt mit Iteratoren.
Naja.
Das dokumentiert jetzt wieder anders, wenn man nur die Signatur sieht.
Das ist dann ein "diese Funktion verarbeitet eine Menge an Elementen, sie kann on-the-fly beliebig viele neue erzeugen oder löschen".
Besser wärestd::array<int, 3> funktion(const std::array<int, 2> &);Das heißt: Diese Funktion verarbeitet eine Menger von 2 Elementen und erzeugt daraus 3 neue. Es hat einen größeren Dokumentationswert, ist allerdings immer noch nicht dasselbe, was die Pointer/Referenzen dokumentieren.
Und mit Iteratoren hätte man: Diese Funktion verarbietet irgendeine Sequenz an Werten. Auch nicht das, was eine Referenz sagt.
Den höchsten Dokumentationsgehalt hat man aber immer noch mit einer eigens konstruiertem Typen(typedef).
-
@MNowo:
Du hast recht: Zeiger gehen auch. Mancher bevorzugt auch Zeiger vor non-const Referenzen.Eventuell gehöre ich künftig auch dazu, nachdem ich gestern über align gelesen habe (http://en.cppreference.com/w/cpp/memory/align)...
Das ist schon eine rechte Sauerei, wenn man nix böses denkt, die Signatur überfliegt(!) und nur das Beispiel liest...
-
Verzeihung wenn ich ein bischen doof Frage aber was meint ihr denn die
ganze Zeit mit "Signatur" von funktionen und dergleichen der Begriff
ist mir ehrlich gesagt noch nie untergekommen.
-
MNowo schrieb:
Verzeihung wenn ich ein bischen doof Frage aber was meint ihr denn die
ganze Zeit mit "Signatur" von funktionen und dergleichen der Begriff
ist mir ehrlich gesagt noch nie untergekommen.Ich habe den Begriff ehrlich gesagt falsch verwendet.
Ich hätte streng genommen eigentlich die Funktionsdeklaration sagen müssen, schließlich bezog ich mich auch auf den Rückgabewert, der bei nicht-Templates nicht zur Signatur gehört.
Die Signatur einer Funktion bezeichnet alle Informationen, die beim Überladen wichtig sind.
Das sind u.a. der Name, der Typ und die Reihenfolge der Paramater etc.
-
Acho okay vielen dank

-
Nathan schrieb:
Naja.
Das dokumentiert jetzt wieder anders, wenn man nur die Signatur sieht.
Das ist dann ein "diese Funktion verarbeitet eine Menge an Elementen, sie kann on-the-fly beliebig viele neue erzeugen oder löschen".Ja, aber das kann sowieso jede Funktion intern ohne das man es ihr an der Signatur ansehen würde.
Nathan schrieb:
Besser wäre
std::array<int, 3> funktion(const std::array<int, 2> &);Das heißt: Diese Funktion verarbeitet eine Menger von 2 Elementen und erzeugt daraus 3 neue. Es hat einen größeren Dokumentationswert,
Kommt halt darauf an was man haben will. Wenn die Funktion Vektoren einer beliebigen Länge nehmen soll oder x sehr groß ist geht das halt eh nicht mehr. Und dann würde ich lieber aus Konsistenz-Gründen auch bei Funktionen mit kleinem x nen std::vector nehmen.
Nathan schrieb:
ist allerdings immer noch nicht dasselbe, was die Pointer/Referenzen dokumentieren.
Versteh ich nicht, x ist doch eine const Referenz bei mir/dir.
-
happystudent schrieb:
Nathan schrieb:
Naja.
Das dokumentiert jetzt wieder anders, wenn man nur die Signatur sieht.
Das ist dann ein "diese Funktion verarbeitet eine Menge an Elementen, sie kann on-the-fly beliebig viele neue erzeugen oder löschen".Ja, aber das kann sowieso jede Funktion intern ohne das man es ihr an der Signatur ansehen würde.
Ja, aber intern. Was eine Funktion intern macht ist wurscht, aber es kann ja sein, dass sie unter gegebenen Umständen vielleicht auch mal 5 Element zurückgibt, oder keins.
Nathan schrieb:
Besser wäre
std::array<int, 3> funktion(const std::array<int, 2> &);Das heißt: Diese Funktion verarbeitet eine Menger von 2 Elementen und erzeugt daraus 3 neue. Es hat einen größeren Dokumentationswert,
Kommt halt darauf an was man haben will. Wenn die Funktion Vektoren einer beliebigen Länge nehmen soll oder x sehr groß ist geht das halt eh nicht mehr. Und dann würde ich lieber aus Konsistenz-Gründen auch bei Funktionen mit kleinem x nen std::vector nehmen.
Wenn sie Vektoren mit beliebiger Länge nehmen soll ist das etwas anderes.
Und nur aus Konsistenzgründen muss man dann halt zusätzlich dokumentieren.Nathan schrieb:
ist allerdings immer noch nicht dasselbe, was die Pointer/Referenzen dokumentieren.
Versteh ich nicht, x ist doch eine const Referenz bei mir/dir.
Nein, die Parameter so als Referenz zu nehmen:
void foo(int x, int &a, int &b);Heißt: foo nimmt ein x und berechnet daraus zwei andere Werte.
std::array<int, 2> foo(int x);Heißt: foo nimmt ein x und berechnet daraus ein Array der Größe 2 (nicht ganz dasselbe wie oben).
std::vector<int> foo(int x);Heißt: foo nimmt ein x und berechnet daraus irgendeine Menge an int-Werten (etwas ganz anderes als oben).
std::vector<int> foo(const std::vector<int> &x);Heißt: foo nimmt eine Menge an Werten und berechnet daraus eine andere Menge an Werten (etwas grundsätzlich und komplett anderes als die erste Version).