Forum: Compiler & IDEs Enum zu char array mappen mit verschiedenen Datentypen


von Peter (Gast)


Lesenswert?

Hallo

Ich stehe mal wieder auf dem Schlauch und bräuchte mal einen Tipp.

Und zwar möchte ich gerne zu den Variablen sensor1 bis 3 die 
dazugehörigen Strings auswählen. Das folgende Beispiel klappt auch 
soweit. Sobald aber z.B. sensor1 einen anderen Datentyp als die 
restlichen Einträge hat, geht das natürlich nicht mehr, weil das 
array_Data ja als uint32_t definiert wurde.

Gibt es einen ähnlich eleganteren Weg, der mit unterschiedlichen 
Datentypen programmiert werden kann? Für mich ist der Vorteil hier, dass 
man über eine Zählvariable direkt die passenden Paare (Wert und Text) 
bekommt.

Bestimmt gibt es eine Möglichkeit mit Strukturen zu arbeiten. Aber da 
müsste man ja die einzelnen Members wieder explizit hinschreiben 
(struc.memberXYZ). Sonst fällt mir echt nichts ein...
1
const char* array_string[] = {"Sensor 1", "Sensor 2", "Sensor 3"};
2
uint32_t* array_Data[] = {&sensor1, &sensor2, &sensor3};
3
4
enum dataSequence{
5
  sensor1,
6
  sensor2,
7
  sensor3,
8
};
9
10
11
void foo(void)
12
{
13
    enum dataSequence s[3];
14
15
    s[0] = sensor1;
16
    s[1] = sensor2;
17
    s[2] = sensor3;
18
19
    int i;
20
    for(i = 0; i < 3; i++)
21
    {
22
23
        print_char_string(array_string[s[i]]);
24
        print_number(array_Data[s[i]]);
25
26
    }
27
}
28
29
void print_char_string(* pointer){}
30
void print_number(* pointer){}

https://www.cs.utah.edu/~germain/PPS/Topics/C_Language/enumerated_types.html

: Verschoben durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das lässt sich nicht compilieren:
1
#include <stdint.h>
2
3
const char* array_string[] = {"Sensor 1", "Sensor 2", "Sensor 3"};
4
uint32_t* array_Data[] = {&sensor1, &sensor2, &sensor3};
5
6
foo.c:4:28: error: 'sensor1' undeclared here (not in a function)
7
 uint32_t* array_Data[] = {&sensor1, &sensor2, &sensor3};
8
                            ^~~~~~~
9
...

Zudem wird später sensor1 als enum deklariert, und davon kann keine 
Adresse genommen wwerden:
1
#include <stdint.h>
2
3
uint32_t sensor1, sensor2, sensor3;
4
5
const char* array_string[] = { "Sensor 1", "Sensor 2", "Sensor 3" };
6
uint32_t* array_Data[] = { &sensor1, &sensor2, &sensor3 };
7
8
enum dataSequence
9
{
10
  sensor1,
11
  sensor2,
12
  sensor3,
13
};
14
15
foo.c:9:3: error: 'sensor1' redeclared as different kind of symbol
16
   sensor1,
17
   ^~~~~~~
18
foo.c:3:10: note: previous declaration of 'sensor1' was here
19
 uint32_t sensor1, sensor2, sensor3;
20
          ^~~~~~~
21
...

von A. S. (Gast)


Lesenswert?

Ich fürchte auch, Du denkst in zuviel Abstraktionen.

Schreibe mal den Code direkt.

Es wird nicht klar, was genau Du denn in array_Data haben möchtest.

Und auch nichtz der Unterschied zwischen der Sensor-Instanz (sensor1..3) 
und dessen Index (auch sensor1..3).

von R. M. (Gast)


Lesenswert?

Enum ist eigentlich nur eine Konstantendefinition, in deinem Beispiel, 
das Gleiche, wie

#define sensor1 0
#define sensor2 1
#define sensor3 1

Nicht als Array zu verstehen, könnte aber den Index für ein Array 
liefern.
Für den Typ, bräuchte dann aber jedes Arrayelement ein weiteres Feld.
1
struct sensors[Anzahl]{
2
 int value;
3
 char type;
4
 };

von Rolf M. (rmagnus)


Lesenswert?

Peter schrieb:
> Hallo
>
> Ich stehe mal wieder auf dem Schlauch und bräuchte mal einen Tipp.
>
> Und zwar möchte ich gerne zu den Variablen sensor1 bis 3 die
> dazugehörigen Strings auswählen.

sensor1 bis 3 sind keine Variablen, sondern Enumeratoren. Sie belegen 
keinen Speicher und existieren nur im Quellcode. Daher ergibt es auch 
keinen Sinn, ihre Adresse zu nehmen.

> Das folgende Beispiel klappt auch soweit.

Das glaube ich dir nicht. Dein Code enthält mehrere Fehler.

> Sobald aber z.B. sensor1 einen anderen Datentyp als die
> restlichen Einträge hat, geht das natürlich nicht mehr, weil das
> array_Data ja als uint32_t definiert wurde.

sensor1 bis 3 sind alle vom Typ enum dataSequence.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kann man natürlich alles machen; unten als Fingerübung in C.

Ansonsten kann ich nur bekräftign, was Achim geschrieben hat: Das sieht 
schwer aus nach Über-Abstaktion.

In C++ ließe sich das alles kompakter formulieren, aber das Problem der 
Über-Abstraktion löst auch C++ nicht (statt der switch/case hätte man 
dann vtables).
1
#include <stdint.h>
2
#include <inttypes.h>
3
#include <stdlib.h>
4
#include <stdio.h>
5
6
typedef enum
7
{
8
  TYP_A,
9
  TYP_B,
10
  TYP_C,
11
  N_TYPES
12
} sensor_typ_t;
13
14
// 3 verschiedene Sensor-Typen, wobei die 1. Komponente bei allen Typen
15
// gleich ist, um damit spaeter Union sensor_t unterscheiden zu koennen.
16
17
typedef struct
18
{
19
    const sensor_typ_t typ;
20
    const char *name;
21
    uint32_t data;
22
} sensorA_t;
23
24
typedef struct
25
{
26
    const sensor_typ_t typ;
27
    const char *name;
28
    int data[2];
29
} sensorB_t;
30
31
typedef struct
32
{
33
    const sensor_typ_t typ;
34
    uint8_t data[4];
35
    const char *name;
36
} sensorC_t;
37
38
// Union fuer alle 3 Sensor-Typen: Typ des Sensors laesst sich
39
// am ersten Feld .typ bzw. .senorA.typ erkennen.
40
41
typedef union
42
{
43
    const sensor_typ_t typ;
44
    sensorA_t sensorA;
45
    sensorB_t sensorB;
46
    sensorC_t sensorC;
47
} sensor_t;
48
49
// Erschaffe 4 Sensoren vom Typ A, B, C, C.
50
51
sensor_t sensors[] =
52
{
53
    {
54
        .sensorA = { .typ = TYP_A, .name = "Sensor 1", .data = 1234 }
55
    },
56
    {
57
        .sensorB = { .typ = TYP_B, .name = "Sennsorr 2", .data = { 12, 34 } }
58
    },
59
    {
60
        .sensorC = { .typ = TYP_C, .name = "Sen 3", .data = { 1, 2, 3, UINT8_MAX } }
61
    },
62
    {
63
        .sensorC = { .typ = TYP_C, .name = "Sen 4", .data = { 5, 6, 7, INT8_MAX } }
64
    },
65
};
66
67
68
__attribute__((__noreturn__))
69
static void bug (const sensor_t *s)
70
{
71
    printf ("BUG %p\n", s);
72
    exit (EXIT_FAILURE);
73
}
74
75
// Ausgabe
76
77
static void print_typ (const sensor_t *s)
78
{
79
    if (s->typ >= N_TYPES)
80
        bug (s);
81
82
    printf (".typ = %d = '%c'\n", s->typ, 'A' + s->typ);
83
}
84
85
static void print_name (const sensor_t *s)
86
{
87
    printf (".name = \"");
88
    switch (s->typ)
89
    {
90
        default: bug (s); break;
91
        case TYP_A: printf ("%s", s->sensorA.name); break;
92
        case TYP_B: printf ("%s", s->sensorB.name); break;
93
        case TYP_C: printf ("%s", s->sensorC.name); break;
94
    }
95
    printf ("\"\n");
96
}
97
98
static void print_data (const sensor_t *s)
99
{
100
    printf (".data = ");
101
102
    switch (s->typ)
103
    {
104
        default: bug(s); break;
105
106
        case TYP_A:
107
            printf ("%" PRIu32, s->sensorA.data);
108
            break;
109
110
        case TYP_B:
111
            printf ("[ %d, %d ]", s->sensorB.data[0], s->sensorB.data[1]);
112
            break;
113
114
        case TYP_C:
115
            printf ("[ %" PRIu8 ", %" PRIu8 ", %" PRIu8 ", 0x%02" PRIx8 " ]",
116
                    s->sensorC.data[0], s->sensorC.data[1],
117
                    s->sensorC.data[2], s->sensorC.data[3]);
118
            break;
119
    }
120
    printf ("\n");
121
}
122
123
void print_sensor (const sensor_t *s)
124
{
125
    printf ("address = %p\n", s);
126
    print_typ (s);
127
    print_name (s);
128
    print_data (s);
129
    printf ("\n");
130
}
131
132
void print_sensors (const sensor_t *s, size_t n_sensors)
133
{
134
    printf ("\n#######\n# Sensors = %d\n\n", n_sensors);
135
    for (size_t i = 0; i < n_sensors; i++)
136
    {
137
        printf ("# %d:\n", i + 1);
138
        print_sensor (s++);
139
    }
140
}
141
142
#define ARRAY_SIZE(X) (sizeof (X) / sizeof (*X))
143
144
int main (void)
145
{
146
    print_sensors (sensors, ARRAY_SIZE (sensors));
147
148
    sensor_t *s = &sensors[3];
149
    s->sensorC.name = "Sensor C.2";
150
    s->sensorC.data[2] = 42;
151
    print_sensors (s, 1);
152
153
    // s->sensorC.typ = TYP_A;  //// error: assignment of read-only member 'typ'
154
}

Ausgabe:
1
#######
2
# Sensors = 4
3
4
# 1:
5
address = 0x20e
6
.typ = 0 = 'A'
7
.name = "Sensor 1"
8
.data = 1234
9
10
# 2:
11
address = 0x216
12
.typ = 1 = 'B'
13
.name = "Sennsorr 2"
14
.data = [ 12, 34 ]
15
16
# 3:
17
address = 0x21e
18
.typ = 2 = 'C'
19
.name = "Sen 3"
20
.data = [ 1, 2, 3, 0xff ]
21
22
# 4:
23
address = 0x226
24
.typ = 2 = 'C'
25
.name = "Sen 4"
26
.data = [ 5, 6, 7, 0x7f ]
27
28
29
#######
30
# Sensors = 1
31
32
# 1:
33
address = 0x226
34
.typ = 2 = 'C'
35
.name = "Sensor C.2"
36
.data = [ 5, 6, 42, 0x7f ]

von STK500-Besitzer (Gast)


Lesenswert?

Text und Sensor-Datentyp gehören zusammen?!
Also eine struct "Sensor_struct"

Der Sensor-Typ kann unterschiedlich sein?
Also eine Union "Sensor_union".

Die Sensor_struct besteht also aus einem Char-Array und einer 
Sensor_union".

Daraus dann ein Array "Sensor_array" erstellen.
1
union Sensor_union{
2
  // die verschiedenen Ergebnistypen
3
};
4
5
6
typdef struct {
7
  char Name[9];
8
  union Sensor_union Sensor_data;
9
}Sensor_struct;
10
11
12
Sensor_struct Sensor_array[3];
Oder?

von Peter (Gast)


Lesenswert?

Guten Morgen.

Vielen Dank für die teils ausführlichen Antworten.


Ich hatte mich beim Vereinfachen des Codes verschrieben.
Sollte so aussehen:
1
const char* array_string[] = {"Sensor 1", "Sensor 2", "Sensor 3"};
2
uint32_t* array_Data[] = {&var_sensor1, &var_sensor2, &var_sensor3};
3
4
enum dataSequence{
5
  sensor1,
6
  sensor2,
7
  sensor3,
8
};

So lässt es sich aber bei mir compilieren und richtig ausführen.

Da komme ich wohl nicht drumherum mir verschiedene Strukturen zu 
schreiben.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter schrieb:
> Sollte so aussehen:

Schön. Aber was soll das? Welches Problem willst Du damit eigentlich 
lösen?

von A. S. (Gast)


Lesenswert?

Peter schrieb:
> So lässt es sich aber bei mir compilieren und richtig ausführen

Dann lass "s[3]" einfach weg und arbeite direkt mit den enums oder dem 
Index ....

Peter schrieb:
1
void foo(void)
2
{
3
    for(int i = 0; i < 3; i++)
4
    {
5
        print_char_string(array_string[i]);
6
        print_number(array_Data[i]);
7
8
    }
9
    /* oder nur einer ... */
10
    print_char_string(array_string[sensor2]);
11
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Johann L. schrieb:

> In C++ ließe sich das alles kompakter formulieren, aber das Problem der
> Über-Abstraktion löst auch C++ nicht (statt der switch/case hätte man
> dann vtables).

Nein, denn man muss nicht notwendigerweise Laufzeitpolymorphie (s.o. 
vtables) verwenden.

Er möchte ja einfach "nur" generischen Code haben. Und das würde man in 
C++ ganz einfach mit statischer Polymorphie lösen.

Es steht zwar in der Fragestellung nicht explizit drin, doch ich vermute 
mal stark, dass es eine reine C-Frage ist. Und da C nun mal eine 
nicht-generische Sprache ist, kann man das Problem nur mit 
poor-mans-polymorphism lösen.

von René H. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Johann L. schrieb:
>
>> In C++ ließe sich das alles kompakter formulieren, aber das Problem der
>> Über-Abstraktion löst auch C++ nicht (statt der switch/case hätte man
>> dann vtables).
>
> Nein, denn man muss nicht notwendigerweise Laufzeitpolymorphie (s.o.
> vtables) verwenden.
>
> Er möchte ja einfach "nur" generischen Code haben. Und das würde man in
> C++ ganz einfach mit statischer Polymorphie lösen.
>
> Es steht zwar in der Fragestellung nicht explizit drin, doch ich vermute
> mal stark, dass es eine reine C-Frage ist. Und da C nun mal eine
> nicht-generische Sprache ist, kann man das Problem nur mit
> poor-mans-polymorphism lösen.

Hat man Dir in der Schule oft das Pausenbrot geklaut?

Sry, der Wissensstand vom TO kommt klar raus.

Grüsse,
René

von DPA (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Es steht zwar in der Fragestellung nicht explizit drin, doch ich vermute
> mal stark, dass es eine reine C-Frage ist. Und da C nun mal eine
> nicht-generische Sprache ist, kann man das Problem nur mit
> poor-mans-polymorphism lösen.

Bei C-Structs gibt es keine Vererbung, aber das ist ein Vorteil, kein 
Nachteil, denn man kann stattdessen Aggregation nutzen:

Ungetestet:
1
enum sensor_type {
2
  SENSOR_TYPE_A,
3
  SENSOR_TYPE_B
4
};
5
6
struct sensor {
7
  enum sensor_type type;
8
  const char* name;
9
};
10
11
struct light_sensor {
12
  struct sensor sensor;
13
  int wavelength;
14
};
15
16
struct audio_sensor {
17
  struct sensor sensor;
18
  float min_freq, max_freq, db_factor;
19
};
20
21
struct light_sensor light_sensor_1 = {
22
  .sensor = {
23
    .name = "light 1"
24
  },
25
  .wavelength = 123
26
};
27
28
struct audio_sensor audio_sensor_1 = {
29
  .sensor = {
30
    .name = "audio 1"
31
  },
32
  .min_freq = 100,
33
  .max_freq = 100000,
34
  .db_factor = 12.3
35
};
36
37
struct sensor* sensor_list[] = {
38
  &light_sensor_1.super,
39
  &audio_sensor_1.super
40
};
41
size_t sensor_count = sizeof(sensor_list)/sizeof(*sensor_list);
42
43
int main(){
44
  for(size_t i=0; i<sensor_count; i++)
45
    printf("sensor: ", sensor_list[i]);
46
}

In go ist das noch etwas schöner. Um von der Liste wieder auf den 
derived typ zugreifen zu können braucht man einen upcast, aber das ist 
auch bei c++ nicht anders.

von DPA (Gast)


Lesenswert?

DPA schrieb:
> printf("sensor: ", sensor_list[i]);

Edit, sollte 'printf("sensor: %s\n", sensor_list[i]->name);' sein.

Beitrag #5467200 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

DPA schrieb:
> Wilhelm M. schrieb:
>> Es steht zwar in der Fragestellung nicht explizit drin, doch ich vermute
>> mal stark, dass es eine reine C-Frage ist. Und da C nun mal eine
>> nicht-generische Sprache ist, kann man das Problem nur mit
>> poor-mans-polymorphism lösen.
>
> Bei C-Structs gibt es keine Vererbung, aber das ist ein Vorteil, kein
> Nachteil, denn man kann stattdessen Aggregation nutzen:

Von Vererbung hatte ich gar nicht gesprochen.

> In go ist das noch etwas schöner. Um von der Liste wieder auf den
> derived typ zugreifen zu können braucht man einen upcast,

Du meinst hier einen "down-cast" oder besser eine "cross-cast", da es ja 
keine Vererbung und damit kein Liskov gibt, wie Du oben selbst sagst.

Willst Du nun Deine Liste verwenden, muss Du nun (wie Johann es oben mal 
exemplarisch gemacht hat) zu Fuß anhand eines Diskriminators (etwa per 
switch) entscheiden, um ein type-dispatching durchzuführen. Dann sind 
wir bei dem oben von mir genannten poor-mans-polymorphism.

von DPA (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Willst Du nun Deine Liste verwenden, muss Du nun (wie Johann es oben mal
> exemplarisch gemacht hat) zu Fuß anhand eines Diskriminators (etwa per
> switch) entscheiden, um ein type-dispatching durchzuführen. Dann sind
> wir bei dem oben von mir genannten poor-mans-polymorphism.

Der springende Punkt ist doch aber gerade, dass das bei C++ ebenso ist, 
solange die abgeleiteten Typen unterschiedliche Funktionens sets haben. 
Bei Funktionen, die nur die Basisklasse benötigen, muss man ebenfalls in 
beiden fällen nicht casten. Nur wenn man mal eine Funktion überladen 
muss, dann hat man einen Cast mehr. Dafür spart man sich die ganzen 
Probleme, die Vererbung mit sich bringen würde. Keine sich 
überschneidenden Namensräume zu haben finde ich vereinfacht vieles.

von Wilhelm M. (wimalopaan)


Lesenswert?

DPA schrieb:
> Wilhelm M. schrieb:
>> Willst Du nun Deine Liste verwenden, muss Du nun (wie Johann es oben mal
>> exemplarisch gemacht hat) zu Fuß anhand eines Diskriminators (etwa per
>> switch) entscheiden, um ein type-dispatching durchzuführen. Dann sind
>> wir bei dem oben von mir genannten poor-mans-polymorphism.
>
> Der springende Punkt ist doch aber gerade, dass das bei C++ ebenso ist,
> solange die abgeleiteten Typen unterschiedliche Funktionens sets haben.

Nein, wenn sie überschrieben sind, macht es der Compiler per vtable.

> Bei Funktionen, die nur die Basisklasse benötigen, muss man ebenfalls in
> beiden fällen nicht casten.

Da ich dann nur den statischen Typ verwende, benutze ich auch keine 
Laufzeitpolymorphie. Dann brauch ich das ganze Konstrukt nicht.

> Nur wenn man mal eine Funktion überladen
> muss, dann hat man einen Cast mehr.

Genau, sagte ich ja oben. Bei C++ braucht man (wegen vtable) keinen 
down-cast.

> Dafür spart man sich die ganzen
> Probleme, die Vererbung mit sich bringen würde.

Die wären?

> Keine sich
> überschneidenden Namensräume zu haben finde ich vereinfacht vieles.

Wo kommt das in dem Beispiel vor?

Wie ich oben schon sagte, kann man es auch (oft besser) mit stat. 
Polymorphie lösen.

: Bearbeitet durch User
von Zweig (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Wie ich oben schon sagte, kann man es auch (oft besser) mit stat.
> Polymorphie lösen.

wie würde das denn aussehen?

von DPA (Gast)


Lesenswert?

Wilhelm M. schrieb:
>> Der springende Punkt ist doch aber gerade, dass das bei C++ ebenso ist,
>> solange die abgeleiteten Typen unterschiedliche Funktionens sets haben.
>
> Nein, wenn sie überschrieben sind, macht es der Compiler per vtable.

Nein, unterschiedliche Funktions sets, nicht identische. Du bringst 
genau den fall, den ich spezifisch ausgeschlossen hatte.

>> Bei Funktionen, die nur die Basisklasse benötigen, muss man ebenfalls in
>> beiden fällen nicht casten.
>
> Da ich dann nur den statischen Typ verwende, benutze ich auch keine
> Laufzeitpolymorphie. Dann brauch ich das ganze Konstrukt nicht.

Genau, hier verstehen wir uns wieder. Ich würde noch behaupten, dass die 
fälle, wo man direckt schon die Funktion nutzen kann, weil man die 
richtigen Typen schon hat, etwa 80% aller Fälle ausmacht.

>> Nur wenn man mal eine Funktion überladen muss, dann hat man einen Cast
>> mehr.
>
> Genau, sagte ich ja oben. Bei C++ braucht man (wegen vtable) keinen
> down-cast.

Aber nur in diesem Spezialfall, wenn man im übergeordneten Typ eine 
Funktion hat, die man auch überladen kann. Sonst muss man entweder eine 
für den Typ unsinnige einführen, oder doch wieder je nach Typ einen 
anderen downcast machen. In dem nicht unüblichen fall hat man logisch 
dann häufig eine Funktion die die Objekte verarbeiten, und nicht eine 
Funktion die eine logische eigenschaft des Objekts wäre, womit die 
lösung mit überladung zu bestenfalls unschönen Architekturen führt.

>> Dafür spart man sich die ganzen Probleme, die Vererbung mit sich bringen
>> würde.
>
> Die wären?

Siehe nächsten Satz. Ausserdem hat man damit eine unnötige Variation 
etwas zu tun, das auch ohne genausogut geht. Und man kann schnell 
unnötige oder problematische Vererbungen machen, wenn man später merkt 
dass z.B. ein Kreis doch keine spezielle Ellipse ist und umgekehrt. Ohne 
Vererbung würde man garnicht erst auf die Idee kommen, das eine könne 
teil des anderen sein.

>> Keine sich überschneidenden Namensräume zu haben finde ich vereinfacht
>> vieles.
>
> Wo kommt das in dem Beispiel vor?

Wozu muss es?

> Wie ich oben schon sagte, kann man es auch (oft besser) mit stat.
> Polymorphie lösen.

Finde ich nicht. Ist übrigens auch nicht im Beispiel.

von Wilhelm M. (wimalopaan)


Lesenswert?

DPA schrieb:
> Aber nur in diesem Spezialfall, wenn man im übergeordneten Typ eine
> Funktion hat, die man auch überladen kann.

Ich denke, Du meinst: überschreiben.

> Sonst muss man entweder eine
> für den Typ unsinnige einführen, oder doch wieder je nach Typ einen
> anderen downcast machen.

Wenn Du das machen "musst", deutet das fast immer auf eine falsche 
Modellierung hin. Denn Du benutzt dann eben nicht das Interface. Kann 
man aber per NVI lösen.

>>> Dafür spart man sich die ganzen Probleme, die Vererbung mit sich bringen
>>> würde.
>>
>> Die wären?
>
> Siehe nächsten Satz. Ausserdem hat man damit eine unnötige Variation
> etwas zu tun, das auch ohne genausogut geht.

Verstehe nicht, was Du meinst.

> Und man kann schnell
> unnötige oder problematische Vererbungen machen, wenn man später merkt
> dass z.B. ein Kreis doch keine spezielle Ellipse ist und umgekehrt. Ohne
> Vererbung würde man garnicht erst auf die Idee kommen, das eine könne
> teil des anderen sein.

Konformanz-Verletzungen gibt auch anderswo.

>>> Keine sich überschneidenden Namensräume zu haben finde ich vereinfacht
>>> vieles.
>>
>> Wo kommt das in dem Beispiel vor?
>
> Wozu muss es?

Wenn Du es erwähnst.

von Wilhelm M. (wimalopaan)


Lesenswert?

Zweig schrieb:
> Wilhelm M. schrieb:
>> Wie ich oben schon sagte, kann man es auch (oft besser) mit stat.
>> Polymorphie lösen.
>
> wie würde das denn aussehen?

Mal ein einfaches Beispiel:
1
#include <cstdint>
2
#include <array>
3
#include <tuple>
4
#include <iostream>
5
6
struct DevA;
7
struct DevB;
8
struct DevC;
9
10
template<typename Device, typename ValueType, auto Size>
11
struct Sensor {
12
    template<typename Stream>
13
    Stream& out(Stream& stream) {
14
        return stream << Size << '\n'; // zu erweitern ...
15
    }
16
private:
17
    std::array<ValueType, Size> mData;
18
};
19
20
std::tuple sensors{
21
    Sensor<DevA, uint8_t, 10>{}, 
22
    Sensor<DevB, uint32_t, 100>{},
23
    Sensor<DevC, double, 5>{}
24
};
25
26
int main() {
27
    std::apply([](auto&... s){
28
        (s.out(std::cout), ...);        
29
    }, sensors);
30
}

von DPA (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Verstehe nicht, was Du meinst.

Ich bezihe mich auf die 2 Sätze des Zitats, die du auseinander genommen 
hast. Der zweite ist eine folge des anderen.

von Zweig (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Mal ein einfaches Beispiel:

Und wo ist da das enum und wie spreche ich einen von den drei Sensoren 
an.
?

von Wilhelm M. (wimalopaan)


Lesenswert?

Zweig schrieb:
> Wilhelm M. schrieb:
>> Mal ein einfaches Beispiel:
>
> Und wo ist da das enum und wie spreche ich einen von den drei Sensoren
> an.
> ?

Im OP stand ja auch nichts von Sensorfunktionen (außer den Namen 
auszugeben und einen Wert). Also, was möchtest Du denn machen?

von jzjjf (Gast)


Lesenswert?

Peter schrieb:
> const char* array_string[] = {"Sensor 1", "Sensor 2", "Sensor 3"};
> uint32_t* array_Data[] = {&sensor1, &sensor2, &sensor3};
>
> enum dataSequence{
>   sensor1,
>   sensor2,
>   sensor3,
> };
>
> void foo(void)
> {
>     enum dataSequence s[3];
>
>     s[0] = sensor1;
>     s[1] = sensor2;
>     s[2] = sensor3;
>
>     int i;
>     for(i = 0; i < 3; i++)
>     {
>
>         print_char_string(array_string[s[i]]);
>         print_number(array_Data[s[i]]);
>
>     }
> }
>
> void print_char_string(* pointer){}
> void print_number(* pointer){}



ist nicht das genau das gleiche?
1
const char* array_string[] = {"Sensor 1", "Sensor 2", "Sensor 3"};
2
uint32_t*   array_Data[] = {&sensor1, &sensor2, &sensor3};
3
4
enum{
5
  sensor1 = 0,
6
  sensor2,
7
  sensor3,
8
  sensormax
9
};
10
11
void foo(void)
12
{
13
    int i;
14
    for(i = 0; i < sensormax ; i++)
15
    {
16
        print_char_string(array_string[i]);
17
        print_number(array_Data[i]);
18
19
    }
20
}

von Zweig (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Im OP stand ja auch nichts von Sensorfunktionen (außer den Namen
> auszugeben und einen Wert). Also, was möchtest Du denn machen?

Ich hätte gerne mal ein Beispiel bei dem es z.B 3 unterschiedliche
SenorTypen gibt.
Klar gleiche Interface aber unterschiedliche Implementierung.
Da fehlt mir ein Ansatz wie ich z.B über einen enum einer dieser 
Sensoren Typen auswähle, eine Instanz bilde und fortan nur noch mit 
diesem interagiere.

Ist sowas auch ohne vtable möglich?

von Wilhelm M. (wimalopaan)


Lesenswert?

Zweig schrieb:
> Wilhelm M. schrieb:
>> Im OP stand ja auch nichts von Sensorfunktionen (außer den Namen
>> auszugeben und einen Wert). Also, was möchtest Du denn machen?
>
> Ich hätte gerne mal ein Beispiel bei dem es z.B 3 unterschiedliche
> SenorTypen gibt.
> Klar gleiche Interface aber unterschiedliche Implementierung.
> Da fehlt mir ein Ansatz wie ich z.B über einen enum einer dieser
> Sensoren Typen auswähle, eine Instanz bilde und fortan nur noch mit
> diesem interagiere.

Genau das steht doch oben: Du hast da drei unterschiedliche Sensortypen, 
sie werden instanziiert, und dann wird über sie iteriert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.