problem mit numerical_limits<int>::max()



  • 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) )
    #endif
    

    Problem 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
    #endif
    

    Die 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
    #endif
    

    Nein, das Problem ist hier, dass SAVEDMAX nur als Textersetzung für max dient. Die Funktionalität von max wird 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 SAVEDMAX mit max textuell 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
    #endif
    

    Die 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)
    #endif
    

    Worauf 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?


  • Mod

    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
    

  • Mod

    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.



  • camper schrieb:

    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.

    Ich habe irgendwo für gcc geschriebenen Code gesehen, der das verwendet, und ich habe jetzt auch noch einmal gesucht, und das hier:

    http://gcc.gnu.org/onlinedocs/gcc/Push_002fPop-Macro-Pragmas.html

    gefunden.

    camper schrieb:

    Die MSDN-Beschreibung lässt darauf schließen, dass das Ganze nur für Objektmakros funktioniert.

    Siehe unten.

    vlad_tepesch schrieb:

    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
    

    Ich habe das, an dein Beispiel angelehnt, mit dem VS2005, Service Pack 1, versucht:

    #include <limits>
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    #ifdef min 
    #  pragma push_macro("min") 
    #  undef min 
    #  define popmin 
    #endif 
    #ifdef max 
    #  pragma push_macro("max") 
    #  undef max 
    #  define popmax 
    #endif
    
    template<class T> class MyClass
    {
    public:
      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); 
      };
    
    private:
    	int m_sum;
    	int m_min;
    	int m_max;
    	int m_count;
    };
    
    #ifdef popmax 
    #  pragma pop_macro("max") 
    #  undef popmax 
    #endif 
    #ifdef popmin 
    #  pragma pop_macro("min") 
    #  undef popmin 
    #endif
    
    int main(int argc, char* argv[])
    {
    	int a = 6;
    	int b = 7;
    	MyClass<int> test;
        MyClass<int> test2;
    
    	cout << max(a, b) << endl;
    
    	return 0;
    }
    

    und es funktioniert.

    MfG,

    Probe-Nutzer



  • und es funktioniert.

    Der teil funktioniert ja auch, aber die makros min/max, werden nicht richtig redefiniert.

    (ich arbeite mit vc++ 8 SP1)



  • vlad_tepesch schrieb:

    und es funktioniert.

    Der teil funktioniert ja auch, aber die makros min/max, werden nicht richtig redefiniert.

    (ich arbeite mit vc++ 8 SP1)

    Ok, kann ich jetzt nichts weiter dazu sagen, mein Code liefert jedenfalls das Maximum wieder. Aber wir haben hier jetzt auch schon einige Lösungen gesehen, insofern betrachte man die pop_macro/push_macro-Idee nur als eine Anmerkung von mir.

    MfG,

    Probe-Nutzer


  • Mod

    Probe-Nutzer schrieb:

    Ich habe irgendwo für gcc geschriebenen Code gesehen, der das verwendet, und ich habe jetzt auch noch einmal gesucht, und das hier:

    http://gcc.gnu.org/onlinedocs/gcc/Push_002fPop-Macro-Pragmas.html

    gefunden.

    Bei der PDF-Version fehlen die Abschnitte 5.52.11 und 5.52.12 - das müsste man gewusst haben... 🙄


Anmelden zum Antworten