constexpr Instanzen wo am besten deklarieren?



  • Ich habe eine Klasse erstellt die Flags repräsentiert. Mit constexpr konstruktor und constexpr +-Operator lassen sich damit Flags zur kompilezeit addieren was ich sehr elegant finde, da es Geschwindigkeit, Typsicherheit und Komfort vereint. Jetzt würde ich gerne eine Reihe von Flags vordefinieren, die man dann je nach Bedarf kombinieren kann. Die erste Idee war, dass ich die einfach als static constexpr in die Klasse lege, aber das geht nicht, da der Kompiler dazu die vollständige Definition der Klasse bräuchte. Was geht, ist die Objekte neben die Klasse in den Header zu legen aber dann wären die ja global, was wohl sehr ungünstig wäre. Ich könnte die noch in einen eigenen Unternamensraum legen, aber optimal scheint mir das auch nicht zu sein. Was meint ihr? Gibt es da eine bessere Lösung?


  • Mod

    Dafür braucht man doch keine Klasse. Nimm einfach int .

    da es Geschwindigkeit, Typsicherheit und Komfort vereint.

    alles nur Blabla. Worum geht es überhaupt? Flags die mehr als nur sich selbst repräsentieren?



  • Der drunterliegende Typ ist ein 8 bit unsigned integer. Die Flags gehören zu einem Kommunikations-Protokoll. Zum einen möchte ich nicht, das hier verschiedene Flagfeldtypen durcheinanderkommen, da es von denen recht viele gibt, zudem möchte ich in Code nicht ständig Bitoperationen mit #define Kostanten machen nur um zu überprüfen ob ein bestimmtes bit gesetzt ist. Auch habe ich dann gleich den Ausgabeoperator mit dabei, was sehr praktisch ist. Letztendlich orientiere ich mich damit auch an Stroustrups Rat zu "Type-rich Interfaces".



  • TNA schrieb:

    Die erste Idee war [...] static [...]. aber dann wären die ja global, was wohl sehr ungünstig wäre.

    Was genau ist an statisch so viel besser als global? Ist es objekt-orientierter?



  • Nexus schrieb:

    Was genau ist an statisch so viel besser als global? Ist es objekt-orientierter?

    Das läge dann halt im selben Scope wie die Klassenmethoden. Das scheint mir irgendwie passender und intuitiver zu sein als es in einen eigenen Namespace zu legen für den ich mir überhaupt erst mal einen sinnvollen Namen ausdenken müsste.



  • Machs doch so, wie man es mit enum ein Jahrzehnt lang gemacht hat:

    namespace Color
    {
        class Type {...};
    
        constexpr Type Yellow = ...;
    }
    


  • Ich denke da wird es wohl drauf hinauslaufen. Ist in etwa das was ich jetzt habe und bei näherer Betrachtung gar nicht so schlecht.


  • Mod

    Und was spricht hier gegen enum?



  • camper schrieb:

    Und was spricht hier gegen enum?

    enum FileMode {
      create=1, append=2, binary=4, temp=8, unbuffered=16, 
    };
    void File::open(string name,Mode mode);//klappt nicht wegen
    ...
    File f;
    f.open("hallo",FileMode::append+FileMode::binary);
    

    und

    void File::open(string name,int mode);//stinkt wegen
    
    File f;
    f.open("hallo",OtherLib::append+OtherLib::binary);
    

  • Mod

    FileMode operator+(FileMode lhs, FileMode rhs)
    {
        return static_cast<FileMode>( lhs + rhs );
    }
    


  • Es gibt auch noch std::integral_constant .


  • Mod

    ScottZhang schrieb:

    Es gibt auch noch std::integral_constant .

    Wissen wir. Und?



  • http://en.cppreference.com/w/cpp/types/integral_constant
    Rechnen + Vergleichen als Antwort auf

    zur kompilezeit addieren ... Type-rich Interfaces ... nicht ständig Bitoperationen mit #define Kostanten machen ...


  • Mod

    integral_constant löst überhaupt nichts, es hat nämlich keinen Vorteil gegenüber enum .



  • integral_constant löst überhaupt nichts

    Koenntest du bitte in eigenen Worten beschreiben von welchem Problem du sprichst!



  • Arcoth schrieb:

    ScottZhang schrieb:

    Es gibt auch noch std::integral_constant .

    Wissen wir. Und?

    Wer ist "Wir", du und der Threadersteller?

    Arcoth schrieb:

    integral_constant löst überhaupt nichts, es hat nämlich keinen Vorteil gegenüber enum.

    Ich kann nur hoffen, dass der zweite Teil des Satzes nich als Begründung für die Aussage des ertsen Teil des Satzes her halten muss.


  • Mod

    knivil schrieb:

    integral_constant löst überhaupt nichts

    Koenntest du bitte in eigenen Worten beschreiben von welchem Problem du sprichst!

    Kombinierbare Flags mit möglichst wenig Aufwand bereitstellen (keine eigenen Klassen, keine Überladungen, lediglich Bereitstellen der Namen)

    Für enums bietet sich bspw. so etwas an:

    #include <iostream>
    
    enum FileMode
    {
    	create=1, append=2, binary=4, temp=8, unbuffered=16,
    };
    
    template<typename T>
    void Test( T );
    
    template< typename A, typename B, typename =void >
    struct implicitly_convertible : std::false_type {};
    
    template< typename A, typename B >
    struct implicitly_convertible<A, B, decltype( Test<B>(std::declval<A>()) )> : std::true_type {};
    
    template< typename, typename = void >
    struct is_strongly_typed_enum : std::false_type {};
    
    template< typename T >
    struct is_strongly_typed_enum< T, typename std::enable_if<std::is_enum<T>::value>::type > :
    	std::integral_constant<bool, !implicitly_convertible<T, typename std::underlying_type<T>::type>::value> {};
    
    template< typename T, typename = typename std::enable_if< std::is_enum<T>::value && !is_strongly_typed_enum<T>::value >::type >
    T operator+(T lhs, T rhs)
    {
    	using _base = typename std::underlying_type<T>::type;
    	return static_cast<T>( _base{lhs} + _base{rhs} );
    }
    
    void open(FileMode mode){}
    
    int main()
    {
        open( FileMode::binary + FileMode::append );
    }
    

    Wer ist "Wir", du und der Threadersteller?

    Wie wäre es, wenn du mal zeigen würdest, was man mit integral_constant anstellen kann? Darauf hinzuweisen ist nutzlos, weil jeder, der in diesem Thread gepostet hat, integral_constant kennt, und nicht daran erinnert werden braucht.

    Ich kann nur hoffen, dass der zweite Teil des Satzes nich als Begründung für die Aussage des ertsen Teil des Satzes her halten muss.

    Mit 'nichts' meinte ich das Problem. s.o.



  • Wer ist "Wir", du und der Threadersteller?

    Wie wäre es, wenn du mal zeigen würdest, was man mit integral_constant anstellen kann? Darauf hinzuweisen ist nutzlos, weil jeder, der in diesem Thread gepostet hat, integral_constant kennt, und nicht daran erinnert werden braucht.

    Ah oh, ich wusste nicht das int's und enums neu sind ...


  • Mod

    ScottZhang schrieb:

    Ah oh, ich wusste nicht das int's und enums neu sind ...

    🙂 Ein Beispiel, wie das ganze Umsetzen könnte, wäre nett.

    Ich habe nämlich überhaupt keine Ahnung, was du überhaupt meinst, und war angefressen, weil du integral_constant erwähnst, was für mich keinen Sinn ergibt.

    Meinst du das hier? Inwiefern ist das besser (oder überhaupt anders) als eine Enumeration?

    std::integral_constant<int, 1> append;
    std::integral_constant<int, 2> binary;
    
    void open( int mode );
    
    int main()
    {
    	open( append + binary );
    }
    


  • Naja, wenn enums und integral_constant gleichwertig sind, ist ja mein Vorschlag doch nicht so sinnlos (qual der Wahl).

    Ich dachte er will irgendwas zur compile-Zeit auswählen, und will dazu irgendeine Art Flag verwenden. Also muss er die "Flags" als Type codieren. Dazu bietet sich doch std::integral_const an, oder nich?

    Also eher sowas:

    template <typename Mode>
    void open ();
    

Log in to reply