Tausender-Seperator nicht anzeigen



  • Hallo,

    folgender Quelltextausschnitt liegt zugrunde:

    double d;
      d= 123456.789;
    
      //Lokalitaet auf Deutschland
      cout.imbue( std::locale("DE") );  
    
      //Exponentendarstellung abschalten
      cout.setf( ios::fixed );
    
      cout << d;
    

    Ergibt:

    123.456,789
    

    Wie kann ich die Tausender-Trennzeichen abschalten?

    Danke



  • Du könntest eine eigene numpunct<>-Facette schreiben und in das Locale einbinden (wenn du weitere Informationen brauchst, müsste ich zu Hause nachschauen, wie das genau funktioniert).



  • Danke, in der Richtung habe ich einiges gefunden:

    template <class charT>
          class my_numpunct: public std::numpunct_byname<charT>
          {
             public:
             explicit my_numpunct(const char* name, size_t refs= 0);  //??
             protected:
             virtual string do_grouping() const { return "\3"; }
          };//class my_numpunct
    
    // ein deutsches Locale erzeugen
    std::locale loc("DE");
    
    //Auf Basis des deutschen Locale mein neuen numpunct einbinden
    std::locale loc_mod(loc, new my_numpunct<char>("DE") );
    filestr.imbue(loc_mod );
    

    Theoretisch sollte das funktionieren, jedoch fehlt dem Compiler ein Standard-Konstruktor zum initialisieren der Basisklasse numpunct_byname.

    Nach meinem Verständnis hat die Basisklasse numpunct_byname nur einen parametrierten Konstruktor, über dem man z.B. die Landeskennung "DE" übergeben muss.

    Das Problem sollte sich auf folgendes reduzieren lassen:

    struct Basis
      {
      //nur parametrierter Konstruktor
      Basis(int a) {cout << "Basis: " << a << endl;}
      };//Basis
    
    struct Ableitung : public Basis
      {
      Ableitung(int a) // .... wie springe ich hier den
                       // parametrierten Konstruktor der Basisklasse an?
                       // bzw. kann er den nicht autmatisch benutzen?
      };//Ableitung
    

    Bei der Instantiierung von Ableitung sollte zuerst der Basisklassenkonstruktor (aber mit Parameter) und dann der der Ableitung aufgerufen werden.

    Das Problem hatte ich an einigen Stellen schon mal, wie löst man das?



  • Wenn ein Locale eine Formatvorlage für tausender Trennung hat, dann kannst du sie nicht abstellen.
    Der einzige Weg, ist wie von CStoll erwähnt, nen numpunct Facet zu erstellen ohne tausender Trennung.

    Geht so:

    template< typename T >
    struct my_numpunct : numpunct< T >
    {
    public:
    	my_numpunct( size_t refs = 0 )
    		: numpunct< T >( refs )
    	{
    	}
    
    protected:
    	virtual T do_thousands_sep()
    	{
    		return T();
    	}
    };
    
    int main()
    {
    	cout.imbue( locale( locale( "German_germany"), new my_numpunct< char > ) );
    	cout << 10000000;
    }
    

    Für German_germany musst halt den entsprechenden Namen angeben, den dein compiler dafür vorsieht.



  • Hab ne Kleinigkeit vergessen, virtual T do_thousands_sep() muss virtual T do_thousands_sep() const sein.



  • Stichwort Initialisierungsliste:

    my_numpunct::my_numpunct(const char* name,size_t refs)
    : numpunct_byname(name,refs)
    {}
    

    @Any: numpunct_byname ist wohl der bessere Weg - damit kannst du nur einen Ausschnitt aus der Facette neu anpassen (d.h. in dem Fall wird nur das Grouping geändert und der Rest der Facette (Bool-Namen, Komma, etc.) von einem benannten Locale übernommen).

    Ergänzung @Markus: Dieses Grouping würd den Seperator aber anzeigen - gibt lieber "" zurück.



  • War ja auch nur nen Beispiel. Man könnte auch do_grouping überschreiben und damit die Angabe wie formatiert werden soll einfach nicht angeben.
    Und ja byname zu verwenden ist besser, nur wollt ich nicht überall so viel implementierungsspezifisches einbauen.



  • Vielen Dank CStoll & Any für die gute Hilfe.

    Das Problem ist nun wie folgt gelöst:

    //Definition der Facet:
      namespace std
        {
        template <class charT>
          class my_numpunct: public std::numpunct_byname<charT>
          {
          public:
             my_numpunct(const char* name, size_t refs= 0) : numpunct_byname<charT>(name, refs) { }
             virtual basic_string<charT> do_grouping() const { return ""; }
          };//class my_numpunct
        }
    
      std:locale loc= std::locale("DE");    //im Standardfall DE annehmen
    
      //Keine Tausender-Seperatoren
      std::locale loc_mod(loc, new std::my_numpunct<char>("DE") );
      cout.imbue(loc_mod);
    
      //Keine Exponentialdarstellung "wissenschaftlich"
      cout.setf( ios::fixed );
    

    PS: Das mit den Initialisierungslisten habe ich nie verwendet, weil ich das früher als dreckigen Hack verstanden habe. Bei Vererbung ist das jedoch sinnvoll und der einzige saubere Weg.



  • Es ist auch der einzige Weg const-Member und Referenz-Member zu initialisieren.

    Du solltest davon absehen etwas in den namespace std zu schreiben.



  • In Wirklichkeit ist die Klasse my_numpunct eine Unterklasse von der Klasse, bei der ich diese Formatierung brauche.

    Ich hatte das nur durch den Namespace hier dargestellt, damit das unabhängig läuft.


Anmelden zum Antworten