Numeric_limits und Typen
-
vlad_tepesch schrieb:
Die brauch man nicht machen, die gibts schon in algorithms:
std::max und std::minHe he, du bist darauf reingefallen

ich kann mit Makros ein
float a=max(1,0.2);machen. Mit templates nicht. dh, ich kann es schon machen, aber der Code ist enorm... Vorallem wenn man dann noch ein
"max(1,0.2)" also ohne Zuweisung supporten will.Ist nicht ganz trivial - wenn dir einmal langweilig ist versuche das Problem zu lösen, ist ganz interessant (Alexandrescu hat dazu einen Artikel geschrieben, gibt es sicher auch online).
ein typeof von einer funktion geht genauso wenig, oder? da müsste ja sowas wie (double *funname(void)) als typ zurückkommen.
Ich sehe also nicht, wie das hier weiterhefen sollte.doch, geht - zumindest mit dem neuen Standard.
Wichtig ist ja auch dass sowas geht:
decltype(a<b)ein max() mit dem neuen standard wäre dann zB:
template<typename A, typename B> auto max(A const& a, B const& b) -> decltype(a<b) { return a<b ? b : a; }
-
Shade Of Mine schrieb:
template<typename A, typename B> auto max(A const& a, B const& b) -> decltype(a<b) { return a<b ? b : a; }return bool?
jetzt haste mich aber neugierig gemacht, wie max mit dem neuen standard geht.
-
volkard schrieb:
jetzt haste mich aber neugierig gemacht, wie max mit dem neuen standard geht.
arg, das war falsch rum - mein fehler.
muss mal googlen - denn irgendwie gingen expression auswertungen...
-
So, korrekter Code wäre dann:
template<typename A, typename B> auto max(A const& a, B const& b) -> decltype(a<b?b:a) { return a<b ? b : a; }manchmal ist es doch so simpel...
Ob es wirklich geht weiss ich nicht, theoretisch müsste es so gehen und ich habe es in einer c.l.c++.mod diskussion gesehen.
So, newsgroup thread wieder gefunden:
http://groups.google.com/group/comp.lang.c++.moderated/msg/15d528fbdf578267PS:
interessanter Punkt hierbei ist, dass max() daduch by value returned - aber ich denke mit type_traits dürfte das eigentlich kein Problem sein:template<typename A, typename B> auto max(A const& a, B const& b) -> boost::call_traits<decltype(a<b?b:a)>::reference { return a<b ? b : a; }
-
ich kann mit Makros ein
float a=max(1,0.2);machen.
template<typename A, typename B> auto max(A const& a, B const& b) -> decltype(a<b?b:a) { return a<b ? b : a; }Ich weiß noch nicht so recht, ob ich sowas gut finden sollte.
schließlich vergleichst du in so einem Fall Äpfel mit Birnen und gibst eins von beiden zurück, dh der tatsächliche typ steht erst zur laufzeit fest.Das widerspricht komplett den prinzipien einer streng typisierten Sprache, als die c++ mal konzipiert wurde.
Wenn man sowas machen will, sollte man, denke ich eine andere Sprache wählen und nicht eine bestehende noch mehr verwässern und aufweichen.
-
vlad_tepesch schrieb:
Das widerspricht komplett den prinzipien einer streng typisierten Sprache, als die c++ mal konzipiert wurde.
Wenn man sowas machen will, sollte man, denke ich eine andere Sprache wählen und nicht eine bestehende noch mehr verwässern und aufweichen.Bei int/float vielleicht, aber das Problem existiert ja auch bei int32/int64 und sonstigen Vergleichen. Aktuell ist es so, dass ich explizit den größeren Typen angeben muss:
int64 c=max<int64>(a, b);aber wenn wir uns das mit dem neuen Standard ansehen:
auto c = max(a,b);viel besser.
Stell dir ein:
template<typename T> T keine_negativen_zahlen_erlaubt(T n) { return max(0, n); }Generell ist das Problem dass mich der Typ von variablen nie interessiert. Wenn ich 2 Variablen habe die kompatibel zueinander sind, dann reicht mir das. Bsp: int16, int32 und int64 sind für mich identisch solange ich keine overflows produziere. Deshalb sind templates toll, weil ich Code unabhängig vom Typ schreiben kann.
Wenn du dir einmal Sprachen mit Type Inference ansiehst wirst du schnell merken wie Bequem es ist den Typen einer variable nicht kennen zu müssen.
Nur weil du den Typ nicht kennst oder er dich nicht interessiert ist die Sprache ja nicht schwach getypt. mein max() ist streng typisiert und wenn du einen blödsinn machen willst wie zB max("hallo", vector<int>()) dann fliegt dir das um die Ohren. Wenn du aber double und int vergleichen willst, dann ist das ok und er promoted den int zu einem double und liefert dir das. Alles was der Code macht ist das explizite spezifizieren des größeren Typen (wie man es jetzt macht) zu automatisieren.
-
vlad_tepesch schrieb:
template<typename A, typename B> auto max(A const& a, B const& b) -> decltype(a<b?b:a) { return a<b ? b : a; }Ich weiß noch nicht so recht, ob ich sowas gut finden sollte.
schließlich vergleichst du in so einem Fall Äpfel mit Birnen und gibst eins von beiden zurück, dh der tatsächliche typ steht erst zur laufzeit fest.C++ bleibt weiterhin statisch typisiert.
Der Ausdrucka<b?b:ahat in C++ genau einen (statischen) Typ, genau den selben Typ wie er auch ohne decltype hier schon verwendet wird (der "?" Operator ist ja nicht neu). Welcher das ist kannst du dir ja mit dem Funktions-Template Trick anzeigen lassen.
Und genau diesen Typ liefert dann ebendecltype(a<b?b:a).Wenn der Compiler keinen geeigneten Typ finden kann (bzw. genauer: wenn der C++ Standard sagt dass es keinen geeigneten Typ für diesen Ausdruck gibt), dann wird er einen Fehler ausspucken. Auch daran ändert decltype nichts.
Beispiel:
a < b ? "sepp" : 42wird nicht compilieren, genauso wirddecltype(a < b ? "sepp" : 42)nicht compilieren.
-
Das kann doch aber nur als constexpr funktionieren, oder nicht?
decltype(a<b?b:a)muss ja zur Compile-Zeit feststehen; wenn a und b Variablen sind, ist das wohl nicht möglich. Kann sein, dass ich da grad quer denke oder was übersehen hab, aber mir scheint das etwas obskur..
-
Badestrand schrieb:
Das kann doch aber nur als constexpr funktionieren, oder nicht?
decltype(a<b?b:a)muss ja zur Compile-Zeit feststehen; wenn a und b Variablen sind, ist das wohl nicht möglich. Kann sein, dass ich da grad quer denke oder was übersehen hab, aber mir scheint das etwas obskur..
der returntype von ?: bestimmt sich durch integer promotion, das läuft und lief schon immer zur compilezeit.
aber ich muss zugeben, daß ich auch ins schwitzen kam bei dem konstrukt.
-
Hast du zufällig Lust, mir das zu erklären? "Integer Promotion" hatte ich nie gehört, Google hat aber geholfen. Verstehe trotzdem nicht, wie
decltype(a<b?b:a)ausgewertet wird, wie wird denn da "a<b" behandelt, etwa die Limits ihrer Typen?
-
Badestrand schrieb:
wie wird denn da "a<b" behandelt, etwa die Limits ihrer Typen?
Falscher Ansatz.
a<b liefert ein bool, aber das ist fuer den decltype egal.
Wenn ich
short a=7;schreibe, ist es ja auch klar was passiert. 7 ist zwar ein int aber er wird zu einem short promoted mit uU einem werteverlust.
Wenn ich nun
3f + 7d;schreibe, dann muss der ergebnis typ ja vorher feststehen, oder? unabhaengig welche werte die beiden operanden haben. Wir wissen es: double ist das Ergebnis.
Bei a<b?b:a ist es das selbe: das ergebnis ist ein typ der sowohl a als auch b beinhalten kann. Wir wissen ja nicht ob a oder b als ergebnis kommt, deshalb muessen wir beide speichern koennen.
Deshalb geht auch folgendes nicht:
double d = true ? 0.7 : "hallo";obwohl wir wissen dass immer 0.7 als ergebnis raus kommt sind char* und double dennoch inkompatibel und duerfen hier nicht verwendet werden.
decltype(a<b?b:a)macht nun nichts anderes als den typen zu bestimmen den man braucht um sowohl a als auch b beinhalten zu koennen.
uU ist es bei einem
decltype(a+b)logischer?
Ich weiss zwar nicht wieviel a+b ist, aber ich weiss dass short + int = int ist.
Das ganze klappt natuerlich auch mit UDT:
string a; char* b; decltype(a+b) c;c muss vom typ string sein. Denn fuer string + char* finde ich genau einen match, naemlich:
string operator+(string const& a, char const* b);aus der string klasse.
wenn der operator+ mehrdeutig waere, wuerde decltype einen fehler liefern.
in prinzip ist also decltype(a+b) ja nur die kurzschreibweise fuerdecltype(operator+(a,b))
-
Badestrand schrieb:
Hast du zufällig Lust, mir das zu erklären? "Integer Promotion" hatte ich nie gehört, Google hat aber geholfen. Verstehe trotzdem nicht, wie
decltype(a<b?b:a)ausgewertet wird, wie wird denn da "a<b" behandelt, etwa die Limits ihrer Typen?decltype(a<b?b:a) funktioniert gleich wie sizeof(a<b?b:a) - der Compiler guckt einfach was für einen Typ der Ausdruck "a<b?b:a" hat und substituiert dann den typ bzw. bei sizeof die grösse.
es gehen ja auch so dinge wie sizeof(a+b) oder sizeof(my_function()) oder sizeof((my_class().my_function().yet_another_function() << 42) + 23) oder ...
und eben auch mit decltype.