c++ Klassenkonstanten

OP (Firma: privatfrickler.de) #5827175
Lesenswert?

Hallo,

ich habe immer wieder den Fall, dass ich an member Funktionen eine 
Klassenkonstante übergeben möchte um das erwünschte Verhalten zu 
signalisieren.

Ich mache das so:
1
public:
2
    using                   DeviceDirection = int;
3
    const DeviceDirection   InputDevice = 0;
4
    const DeviceDirection   OutputDevice = 1;

das ist eigentlich ganz nett und da nur ich selbst das api benutze, 
stört der Nachteil eigentlich auch nicht: Was mich stört ist, dass man 
einer Memberfunktion, zum Beispiel:
1
void MidiManager::enableDevice(int index, DeviceDirection);

als Konstante (DeviceDirection) jetzt auch einfach einen beliebigen int 
übergeben kann.

Das ist meine Frage. Geht es, und wenn ja, wie, dass ich die Sache so 
gestalten kann, dass ich nur genau die vorgesehenen Konstanten übergeben 
kann und nicht irgendwas konvertierbares?

Mit "nicht kann" meine ich so beiläufig oder aus Versehen, wie in dem 
Beispiel oben, wo ich einfach ->enableDevice(12, 42) schreiben kann 
statt die vorgesehen Konstanten zu verwenden. Ob man das mit Heimtücke 
und Aufwand austricksen kann ist egal, sowas meine ich nicht.

vlg
 Timm
Gast #5827180
Lesenswert?

Timm R. schrieb:
> ...>
> Das ist meine Frage. Geht es, und wenn ja, wie, dass ich die Sache so
> gestalten kann, dass ich nur genau die vorgesehenen Konstanten übergeben
> kann und nicht irgendwas konvertierbares?
>
> Mit "nicht kann" meine ich so beiläufig oder aus Versehen, wie in dem
> Beispiel oben, wo ich einfach ->enableDevice(12, 42) schreiben kann
> statt die vorgesehen Konstanten zu verwenden. Ob man das mit Heimtücke
> und Aufwand austricksen kann ist egal, sowas meine ich nicht.
>
> vlg
>  Timm

Das was du suchst nennt sich strong type. Einen Einstieg ins Thema gibts 
z.B. hier 
https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/
Gast #5827450
Lesenswert?

Rolf M. schrieb:
> Carl D. schrieb:
>> enum
>
> Ja, das ist exakt für sowas gemacht.

Ergänzung einer Ungenauigkeit:

In diesem Fall möchte er TO explizit eine starke Typisierung.
Mit dem von dir zitiertem Ausschnitt könnte man denken, dass ein "enum" 
genügen würde.
Ein einfacher enum (unscoped enum) hat implizite Konvertierungen 
von/nach int. Im ursprünglichen Beitrag von Carl D. stand aber "enum 
class", also  ein scoped enum. Diese haben keine impliziten 
Konvertierungen mit int und können nur über den Namen (oder explizite 
Konvertierungen) verwendet werden.

Und das ist, was der TO verwenden möchte.

https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations
#5827568
Lesenswert?

Ralf C. schrieb:
> Rolf M. schrieb:
>> Carl D. schrieb:
>>> enum
>>
>> Ja, das ist exakt für sowas gemacht.
>
> Ergänzung einer Ungenauigkeit:
>
> In diesem Fall möchte er TO explizit eine starke Typisierung.
> Mit dem von dir zitiertem Ausschnitt könnte man denken, dass ein "enum"
> genügen würde.
> Ein einfacher enum (unscoped enum) hat implizite Konvertierungen
> von/nach int.

Das ist falsch!
Beim Versuch, folgendes C++-Programm zu übersetzen:
1
enum DeviceDirection
2
{
3
    InputDevice = 0,
4
    OutputDevice = 1
5
};
6

7
void enableDevice(int index, DeviceDirection dir)
8
{
9
}
10

11
int main()
12
{
13
    enableDevice(12, 42);
14
}
meldet der Compiler:
1
enum.cpp: In function ‘int main()’:
2
enum.cpp:13:24: error: invalid conversion from ‘int’ to ‘DeviceDirection’ [-fpermissive]
3
     enableDevice(12, 42);
4
                        ^
5
enum.cpp:7:6: note:   initializing argument 2 of ‘void enableDevice(int, DeviceDirection)’
6
 void enableDevice(int index, DeviceDirection dir)
7
      ^~~~~~~~~~~~

Das ist exakt das, was der TO beschrieben hat, was passieren soll.

> Im ursprünglichen Beitrag von Carl D. stand aber "enum
> class", also  ein scoped enum. Diese haben keine impliziten
> Konvertierungen mit int

Einen klassischen enum kann man nur nach int konvertieren, nicht von 
int.
Gast #5827604
Lesenswert?

Rolf M. schrieb:
> Einen klassischen enum kann man nur nach int konvertieren, nicht von
> int.

Gut.

Der TO sei darauf hingewiesen, dass er sich aussuchen kann ob implizite 
Konvertierungen von enum nach int zulässig sein sollen (unscoped enum), 
oder nicht (scoped enum):
1
enum       Foo { A = 0, };
2
enum class Bar { B = 0, };
3

4
void fun()
5
{
6
  Foo::A + 42;  // ok
7
  Bar::B + 42;  // error: no match for ‘operator+’ (operand types are ‘Bar’ and ‘int’)
8
}
OP (Firma: privatfrickler.de) #5827650
Lesenswert?

Hallo,

ich erinnere mich. Von enums hatte ich mich für mich persönlich 
verabschiedet, weil mir überhaupt nicht gefiel, dass die Bezeichner aus 
dem enum in den umgebenden Scope durchsickern.

Das hat natürlich den Vorteil das die Bezeichner für die Konstanten 
eleganter sind.

Der scoped enum gefiel mir früher (TM) nicht, weil mir die Bezeichner 
dadurch zu gesprächig waren, aber ich muss sagen, heute gefällt mir das 
eigentlich sogar:
1
MidiManager::DeviceDirection::Input

Sieht doch eigentlich ganz nett aus. Ich werde also den enum class 
verwenden.

Danke noch mal

vlg
 Timm
#5827715
Lesenswert?

Timm R. schrieb:
> ich erinnere mich. Von enums hatte ich mich für mich persönlich
> verabschiedet, weil mir überhaupt nicht gefiel, dass die Bezeichner aus
> dem enum in den umgebenden Scope durchsickern.

> Der scoped enum gefiel mir früher (TM) nicht, weil mir die Bezeichner
> dadurch zu gesprächig waren, aber ich muss sagen, heute gefällt mir das
> eigentlich sogar

Ja, das ist zu einem gewissen Grad auch Geschmackssache. Ich bin ja auch 
nicht generell gegen enum class. Ich mag nur so lange Bandwurmnamen 
nicht so arg - finde sie schwerer zu erfassen, und der zusätzliche 
Bestandteil DeviceDirection:: gibt mit keine Information, die ich ohne 
ihn nicht hätte.
OP (Firma: privatfrickler.de) #5827772
Lesenswert?

Hallo Rolf,

Rolf M. schrieb:
> finde sie schwerer zu erfassen,

ja das stimmt. Vielleicht stören sie mich heute deswegen nicht mehr so?

Damals (TM) war ich einfach krasser drauf. Lange Sessions und Hauptsache 
die Tasten klappern :-)

Ich habe aber auch den Fluch, dass ich echt viel hin- und herschalten 
muss zwischen verschiedenen Sprachen, vielen macht das nichts, mir 
schon. Ich komme total schnell wieder raus und verwechsle Idiome etc.

Da können lange und selbsterklärende Namen schonmal eine echte Hilfe 
sein :-)

> und der zusätzliche
> Bestandteil DeviceDirection:: gibt mit keine Information, die ich ohne
> ihn nicht hätte.

Aber geiler Punkt! Danke! Ich denke ich werde das Direction rausnehmen! 
Das ist wirklich über. Das Device hilft mir aber.

vlg
Timm

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren