problem mit numerical_limits<int>::max()
-
ich habe ja keinen einfluss darauf, ob das macro da ist, oder nicht:
headerdatei meiner klasse
#include <limits> template<class T> class MyClass { public: MyClass() :m_min(numeric_limits<T>::max()) ,m_max(numeric_limits<T>::min()) {} T m_min; T m_max; }wenn jetzt an irgend einer Stelle im Projekt (die ich nicht kenne und auf die ich keinen Einfluss habe) dieser header includiert wird, wo dieses max, oder min makro präsent ist, gehts net.
-
vlad_tepesch schrieb:
da das verwendete eine templateklasse ist, welche im header implementiert ist, hätte ein undef unvorhersehbare Folgen
das undef hätte nur dann unvorhersehbare Folgen wenn du das Makro das dir irgendwo aus dem windows.h header untergejubelt wurde, auch benutzen willst. Das Makro wird in anderen headern und in deinem Code nicht benutzt, deshalb kannst du es getrost per undef entsorgen, bevor es sich wie hier in deine header schleicht und deine Definitionen verhunzt. Was du hier siehst ist eines der wichtigsten Argumente gegen Makros in Headern, vor allem wenn sie so prägnant kurze namen haben - je geläufiger der Name desto größer die Wahrscheinlichkeit dass irgendwer den Namen woanders benutzt, nicht ahnend dass das Makro ihm den Code zerstört. Deshalb: windows.h nur mit vorherigem #define NOMINMAX benutzen und wenn möglich als allerletztes einbinden, damit diese gruselige Makropolitik dir nicht später eingebundene Header zerpflügen kann.
wenn jetzt an irgend einer Stelle im Projekt (die ich nicht kenne und auf die ich keinen Einfluss habe) dieser header includiert wird, wo dieses max, oder min makro präsent ist, gehts net.
Deshalb solltest du dafür sorgen dass diese bescheuerten Makros nie, nie, nie irgendwo präsent sind, wo du noch Header einbindest oder gar in Headern selbst.
-
vlad_tepesch schrieb:
ich habe ja keinen einfluss darauf, ob das macro da ist, oder nicht
Doch. Makros kann man
#undefen.vlad_tepesch schrieb:
da das verwendete eine templateklasse ist, welche im header implementiert ist, hätte ein undef unvorhersehbare Folgen, es sei denn man könnte die alte definition speichern und danach wieder herstellen.
Wieso brauchst du das Makro nachher überhaupt noch? In C++ sollte das sowieso nicht verwendet werden.
-
meine frage war ja eigendlich, ob ma irgendwie die definition von max sichern kann, dann ein undef und dann redefinieren, ohne dass ich de ursprüngliche definition kenn muss. so ähnich wie mit praga pushes und pops
-
Vor jedem windows.h-Include ganz einfach #define NOMINMAX und fertig.
MfG SideWinder
-
Nexus schrieb:
Doch. Makros kann man
#undefen.das sollte man aber nicht in headern machen, die von anderen benutzt werden
Nexus schrieb:
Wieso brauchst du das Makro nachher überhaupt noch? In C++ sollte das sowieso nicht verwendet werden.
das ändert ja nix daran, dass es automatisch da ist und mancher trotzdem verwendet
-
SideWinder schrieb:
Vor jedem windows.h-Include ganz einfach #define NOMINMAX und fertig.
MfG SideWinder
nur habe ich keinen zugriff auf diese files und muss die umgebung, in der ich includet werde, nehmen, wie ich sie bekomme
-
Es mag sinnvoll sein, statt eines #undef eine Fehlermeldung auszugeben. Denn grundsätzlich ist davon auszugehen, dass es sich hier um einen Konfigurationsfehler handelt, schließlich darf kein Header der Standardbibliothek mit vorhandenem min/max-Makro verwendet werden. z.B. so
#if defined max || defined min #if defined __WINDOWS__ && !defined NOMINMAX #error Please define NOMINMAX before including <windows.h> #else #error This header cannot function properly with min/max-macros defined #endif #endifOder man schwächt das Ganze ab zu einer Warnung mit folgendem #undef
Ein temporäres umdefinieren kann man auch erwägen
#ifdef max #undef max #define max max #endif ... #ifdef max #undef max #define max( a, b ) ( ((b) < (a)) ? (a) : (b) ) #endifProblem hierbei ist natürlich, dass man den vorherigen Inhalt des Makros nicht kennt, und ihn somit nicht sicher wiederherstellen kann.
-
vlad_tepesch schrieb:
ich habe ja keinen einfluss darauf, ob das macro da ist, oder nicht:
headerdatei meiner klasse
#include <limits> template<class T> class MyClass { public: MyClass() :m_min(numeric_limits<T>::max()) ,m_max(numeric_limits<T>::min()) {} T m_min; T m_max; }wenn jetzt an irgend einer Stelle im Projekt (die ich nicht kenne und auf die ich keinen Einfluss habe) dieser header includiert wird, wo dieses max, oder min makro präsent ist, gehts net.
Kann es sein, dass Dir die Includeguards fehlen?
#ifndef __MEIN_HEADER_H__INCLUDED #define __MEIN_HEADER_H__INCLUDED //code #endif
-
camper schrieb:
mit folgendem #undef
Ein temporäres umdefinieren kann man auch erwägen
#ifdef max #undef max #define max max #endif ... #ifdef max #undef max #define max( a, b ) ( ((b) < (a)) ? (a) : (b) ) #endifProblem hierbei ist natürlich, dass man den vorherigen Inhalt des Makros nicht kennt, und ihn somit nicht sicher wiederherstellen kann.
Ich bin mir nicht ganz sicher ob man Makros verschachteln kann (eigentlich will ichs auch nicht wissen weil ichs nicht anwenden will), aber rein hypotetsich, geht sowas?
#ifdef max #define SAVEDMAX max #undef max #endif ... #ifdef SAVEDMAX #define max SAVEDMAX #undef SAVEDMAX #endif(Oh Graus...)
Tachyon schrieb:
Kann es sein, dass Dir die Includeguards fehlen?
#ifndef __MEIN_HEADER_H__INCLUDED #define __MEIN_HEADER_H__INCLUDED //code #endifDie helfen leider auch nicht weiter:
#include <windows.h> //ab hier ist das Makro max definiert und verändert alles was an max noch kommt #include "myheader.h" //jedes Vorkommen von max in myheader.h wird HIER durch das Makro ersetzt - woanders vielleicht nicht...
-
pumuckl schrieb:
Ich bin mir nicht ganz sicher ob man Makros verschachteln kann (eigentlich will ichs auch nicht wissen weil ichs nicht anwenden will), aber rein hypotetsich, geht sowas?
#ifdef max #define SAVEDMAX max #undef max #endif ... #ifdef SAVEDMAX #define max SAVEDMAX #undef SAVEDMAX #endifNein, das Problem ist hier, dass
SAVEDMAXnur als Textersetzung fürmaxdient. Die Funktionalität vonmaxwird eben nicht übertragen.
-
pumuckl schrieb:
[...]
Ich bin mir nicht ganz sicher ob man Makros verschachteln kann (eigentlich will ichs auch nicht wissen weil ichs nicht anwenden will), aber rein hypotetsich, geht sowas?#ifdef max #define SAVEDMAX max #undef max #endif ... #ifdef SAVEDMAX #define max SAVEDMAX #undef SAVEDMAX #endif(Oh Graus...)
Ich denke nicht, da hierbei nur
SAVEDMAXmitmaxtextuell ersetzt wird.pumuckl schrieb:
Tachyon schrieb:
Kann es sein, dass Dir die Includeguards fehlen?
#ifndef __MEIN_HEADER_H__INCLUDED #define __MEIN_HEADER_H__INCLUDED //code #endifDie helfen leider auch nicht weiter:
#include <windows.h> //ab hier ist das Makro max definiert und verändert alles was an max noch kommt #include "myheader.h" //jedes Vorkommen von max in myheader.h wird HIER durch das Makro ersetzt - woanders vielleicht nicht...Ich ging hierbei davon aus, dass eigentlich gar keine Konflikte mit den Windows-Defines bestehen, sondern dass die eigentlich Ursache des Problems die fehlenden Includeguards sind.
-
Tachyon schrieb:
Kann es sein, dass Dir die Includeguards fehlen?
hab ich jetzt mal der einfach halber weggelassen
an campers ersten vorschlag hab ich auch schon gedacht und werd ihn wohl benutzen. (es ist hoffentlich niemand so dämlich die min und max makros umzudefineren, dass sie was anderes machen)
ich hätt halt gehofft das jemand ne andere alternative kennt, das makro zu konservieren, oder den präprozessor für bestimmte codeteile abzuschalten.
ZB mittels pragmas, oder so.pumuckles vorschlag, geht definitv nicht.
-
vlad_tepesch schrieb:
an campers ersten vorschlag hab ich auch schon gedacht und werd ihn wohl benutzen.
Würde ich auch nicht machen. Ich würds einfach analog zu den Standardheadern wie <limits> machen, die auch davon ausgehen, dass niemand so bescheuert ist, ein Makro wie max zu defineren, bevor er die Header einbindet. Du könntest zwar wie vorgehabt nachgeben nach dem Motto "okay, windows.h definiert das Makro max, dem muss ich rechnugn tragen", aber wenn du so anfängst kommt bald eine bestimmt sehr nützliche Bibliothek, die in ihren Headern vielleicht folgendes stehen hat:
#ifndef OHNOEZ #define pair 2 #define vector int[3] #define string const char* #define if( arg ) maybe( (arg) ) #define cout (printf("ich mach dir alles kaputt!"), cerr) #endifWorauf ich hinauswill: mach dir nicht überflüssige Arbeit, nur weil unter Umständen jemand ausversehen ein Makro definiert haben könnte das genauso heißt wie eine Funktion die im Standard vorhanden ist. Es ist nicht deine Aufgabe das wieder gut zu machen. Es ist Aufgabe des makro-Herstellers, seine Kreation möglichst vor der Publizierung zu entsorgen*, bzw. Aufgabe des Klienten, äußerst vorsichtig mit solchen Biblotheken umzugehen.
_____________________
* ich weiß dass windows.h eine C-API ist und mit Standard-C++ daher nichts am Hut haben muss. Umso schlimmer dass alle Welt immernoch fröhlich und ungeschützt die Makrohölle in ihre C++-Codes importiert. Gibts keinen C++ windows.h-Wrapper?
-
Mein erster Vorschlag bestand darin, eine intelligente Fehlermeldung zu produzieren (und das ist auch das Einzige, was ich selbst tun würde - wenn überhaupt).
Grundsätzlich ist es richtig, dass man nicht mit jedem Unfug, den man vor Einbinden des Headers machen kann, umgehen können muss. Praktisch stellt sich aber eher die Frage, ob es in bestimmten bekannten Fällen zuviel verlangt ist. Da eine solche Überprüfung in jedem einzelnen Header die Wartbarkeit nicht fördert, ist sie eher etwas für einen zentralen Konfigurationsheader, den man im Falle einer etwas umfangreicheren Bibliothek ohnehin oft hat, um sich auf das konkrete System, für das kompiliert wird, einzustellen (natürlich muss man sich auch dabei intelligent anstellen: die Überprüfung darf nicht durch include-Guards geschützt sein).
-
Hallo,
es gibt sogar Compiler (Microsoft/g++), die die #pragmas push_macro/pop_macro kennen:
http://msdn.microsoft.com/en-us/library/2bs04eza(VS.80).aspx
MfG,
Probe-Nutzer
-
das scheint ja genau das zu sein was ich suche, leider functioniert das pop_macro irgend wie nich:
#ifdef min # pragma push_macro("min") # undef min # define popmin #endif #ifdef max # pragma push_macro("max") # undef max # define popmax #endif MyClass() :m_count(0) ,m_min(numeric_limits<T>::max()) ,m_max(numeric_limits<T>::min()) ,m_sum(0) {}; MyClass(T i) :m_count(0) ,m_min(numeric_limits<T>::max()) ,m_max(numeric_limits<T>::min()) ,m_sum(0) { operator=(i); }; #ifdef popmax # pragma pop_macro("max") # undef popmax #endif #ifdef popmin # pragma pop_macro("min") # undef popmin #endif
-
Probe-Nutzer schrieb:
Hallo,
es gibt sogar Compiler (Microsoft/g++), die die #pragmas push_macro/pop_macro kennen:
http://msdn.microsoft.com/en-us/library/2bs04eza(VS.80).aspx
MfG,
Probe-Nutzer
In der gcc-Dokumentation kann ich nichts dazu finden. Die MSDN-Beschreibung lässt darauf schließen, dass das Ganze nur für Objektmakros funktioniert.
-
Wenn man die Makros nicht einfach #undefen kann (ja das kommt vor), geht auch folgende Methode (auch wenns nicht mehr ganz so schön aussieht):
#define NO_MACRO MyClass() :m_count(0) ,m_min(numeric_limits<T>::max NO_MACRO ()) ,m_max(numeric_limits<T>::min NO_MACRO ()) ,m_sum(0) {}; MyClass(T i) :m_count(0) ,m_min(numeric_limits<T>::max NO_MACRO ()) ,m_max(numeric_limits<T>::min NO_MACRO ()) ,m_sum(0) { operator=(i); };
-
@derkuchen
danke, es ist zwar wirklich nicht mehr so schön, aber das löst das Problem auf sicherste und unkomplizierteste weise.