fabs() wirkt antiquiert
-
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);int abs(int j);
long int labs(long int j);
long long int llabs(long long int j);Wo ist das Problem, was ist daran antiquiert?
-
Weil templates einfach praktischer wären.
zB für die Verwendung
- innerhalb von templates
- mit eigenen DatentypenEs gibt doch keinen Grund haufenweise Überladunegn zu basteln!
-
Diese sind Teil der C-Bibliothek, es sind auch keine Ueberladungen.
Weil templates einfach praktischer wären.
Subjektiv.
Dann bastele dir doch schnell selbst ein Template:
template <class T> T abs( const T& a ) { return (a<0)?-1*a:a; }Warum sollte denn jeder Scheiss mit im Standard sein, den man als Einzeiler hinschreiben kann ... Auch gibt es Probleme bei der Allgemeingueltigkeit: Was ist 0 fuer einen Typ T, was bedeutet < fuer einen Typ T, was bedeutet -1 bei einem Typ T, was bedeutet * bei einem Typ T? Auch ist im Allgemeinen unklar, was absolut fuer eine Bedeutung hat, bei Punkten im Raum ist es wohl anders als bei reellen Zahlen (hinzu kommt dann noch welche Halbmetrik/Metrik/Norm zu verwenden ist). Da sind die typbezogenen Funktionen der C-Bibliothek schon besser.
Es gibt doch keinen Grund haufenweise Überladunegn zu basteln!
Wie du siehst, gibt es den.
-
knivil schrieb:
Warum sollte denn jeder Scheiss mit im Standard sein, den man als Einzeiler hinschreiben kann ...
Weil es dann so viele Einzeiler-Implementationen wie Programmierer gibt.
-
absolutist schrieb:
Hallöle
Gibt es nicht ein Template die diese Funktion übernimmt? fabs/abs ist äussert nutzlos wenn kein double/int erwünscht ist!
Klar geht das in 2sek selbst, aber ist da nicht was im standard?Ja, gibt es: In
<cstdlib>gibt'sstd::absfürintundlong. In<cmath>gibt'sstd::absfürfloat,doubleundlong double. In <complex> gibt'sstd::absfürcomplex<T>mit einemTals Rückgabewert.Tipp für generischen Code: Schreibe statt
T foo = std::abs(bar);lieber
using std::abs; T foo = abs(bar);innerhalb einer Funktion. Die zweite Version funktioniert dann nicht nur mit den eingebauten Typen, sondern auch noch -- dank ADL -- mit benutzerdefinierten Typen.
Gruß,
SP
-
@knivil: Stell dir vor, ein bisschen muss man beim programmieren schon selber denken. Dein "Argument" könnte man auf jedes template anwenden! :p
@Pizer:
Hört sich gut an, jedoch verstehe ich nicht ganz warum das auch mit benutzerdefinierten Typen geht wenn es doch nur Funktionen für die von dir aufgezählten Typen gibt!?
-
absolutist schrieb:
@knivil: Stell dir vor, ein bisschen muss man beim programmieren schon selber denken. Dein "Argument" könnte man auf jedes template anwenden! :p
Nein, * und < koennen als Operatoren der Klasse implementiert sein und erhalten somit Semantik, aber fuer 0 und 1 bzw. -1 gibt es keinen schoenen allgemeinen Weg. Einfachstes Beispiel ist das Template max. Dort wuerde meine Argumentation fehlschlagen.
-
absolutist schrieb:
@Pizer:
Hört sich gut an, jedoch verstehe ich nicht ganz warum das auch mit benutzerdefinierten Typen geht wenn es doch nur Funktionen für die von dir aufgezählten Typen gibt!?Man muss natürlich eine passende
abs-Funktion für den benutzerdefinierten Typen im selben Namensraum definieren, in der auch der Typ definiert ist:class high_precision_float { //... }; high_precision_float abs(high_precision_float const& x) { //... }Diese Funktion wird dann dank ADL gefunden -- aber nur, wenn du nicht ADL explizit durch eine Qualifizierung (std::abs) umgehst.
Ich hatte dazu mal nen kleinen Artikel geschrieben. Vielleicht ist der ja brauchbar.

Gruß,
SP
-
abs-Funktion für den benutzerdefinierten Typen im selben Namensraum definieren
Wo wir wieder bei Ueberladung sind, das ja absolutist kritisiert hat.
-
knivil schrieb:
Nein, * und < koennen als Operatoren der Klasse implementiert sein und erhalten somit Semantik, aber fuer 0 und 1 bzw. -1 gibt es keinen schoenen allgemeinen Weg. Einfachstes Beispiel ist das Template max. Dort wuerde meine Argumentation fehlschlagen.
Das liegt aber hauptsächlich an deinem schlechten Funktionstemplate. Wenn man es nämlich ein wenig umschreibt, dann fallen so gut wie alle deine Punkte weg:
template<typename T> T abs(T const& val) { return (val < T() ? -val : val); }Zudem, wie es bei allen Templates der Fall ist, wie auch bei allen Algorithmen aus der Standardbibliothek, muss der Typ T halt einem gewissen Konzept folgen. Aber mit der oben genannten Vorgehensweise dürfte man viele Möglichkeiten, abdecken. Man hat auch keine 0 und keine -1 mehr.
Für spezielle Typen, wie zum Beispiel einen Vektor, darf man eine Spezialisierung anbieten. Der Standard erlaubt ja nur, dass man Funktionen aus dem Namensraum
stdspezialisieren darf, aber nichts in diesem Namensraum dazufügen.
Wobei man hier schlussendlich dann wohl auf das gleiche Problem wie mitstd::swapstossen wird. Wodurch eine Überladung, bei welcher man auf ADL setzt, trotzdem benötigt wird. Aber immerhin nur bei gewissen Typen.
Durch den einheitlichen Funktionsnamen hat man zudem einen standardisierten Funktionsnamen. Wodurch alle Funktionen hoffentlich so heissen werden. Weil in C die Überladung fehlt, fehlt dieser einheitliche Namen aktuell vollkommen.Obwohl so ein Funktionstemplate auch ein paar Nachteile hat, sehe ich im allgemeinen allerdings mehr Vorteile gegenüber den aktuellen Möglichkeiten.
Grüssli