Was bedeutet der geheimnisvolle Doppelpunkt?

Ich bin ja keineswegs ein C/C++ Profi, sondern zu hundert Prozent Autodidakt und lerne jeden Tag dazu. Das Lernen geschieht oft durch Lesen und (hoffentlich) Verstehen von eleganten Codelösungen.

Vor kurzem bin ich auf eine sehr elegante und für mich bislang unbekannte “Konstruktion” gestoßen ein Array “abzuarbeiten”. Beispiel:

const uint8_t myLedPins[] = { 10, 11, 12, 13 };
for (uint8_t const &pin : myLedPins)
  pinMode(pin, OUTPUT);

Es geht um die Zeile mit dem Doppelpunkt.

Mir ist schon klar was da passiert: es wird das Array abgearbeitet. Aber wieso?
Was hat es mit dem geheimnisvollen Doppelpunkt auf sich?
Kann mir bitte jemand die entsprechende Kapitelüberschrift im C++ Buch oder einen Suchbegriff nennen.

Die Variante mit dem Doppelpunkt finde ich ziemlich elegant :slight_smile:
Meine bisherige Lösung war etwa so:

const uint8_t myLedPins[] = { 10, 11, 12, 13 };
const uint8_t maxLeds = sizeof(myLedPins) / sizeof(myLedPins[0]);
for (int pin = 0; pin < maxLeds; pin++)
  pinMode(myLedPins[pin], OUTPUT);

Das funktioniert natürlich auch…

Ich habe Konstruktionen mit Doppelpunkten schon in Klassen gesehen - aber Klassen sind mir, ehrlich gesagt, meist ein Klasse zu hoch :slight_smile:
Hat das vielleicht etwas mit Initialisierungslisten zu tun?

Hier der Vollständigkeit halber noch ein lauffähiger Beispiel-Code - man möge mir die Delays nachsehen, es geht dabei nur darum “die Konstruktion mit dem Doppelpunkt” zu testen: :o

const uint8_t myLedPins[] = { 10, 11, 12, 13 };
const uint8_t maxLeds = sizeof(myLedPins) / sizeof(myLedPins[0]);
const uint8_t buttonPin = 7;

void rollEffect() {
  // LEDs der Reihe nach einschalten: mit geheimnisvollem Doppelpunkt :-)
  for (uint8_t const &pin : myLedPins) {
    digitalWrite(pin, HIGH);
    delay(100);
  }
  // LEDs der Reihe nach ausschalten, mit meiner bisherigen Methode
  for (int pin = 0; pin < maxLeds; pin++) {
    digitalWrite(myLedPins[pin], LOW);
    delay(100);
  }
}

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  for (uint8_t const &pin : myLedPins)
    pinMode(pin, OUTPUT);
}

void loop() {
  if (!digitalRead(buttonPin))
    rollEffect();
}

uxomm: Kann mir bitte jemand die entsprechende Kapitelüberschrift im C++ Buch oder einen Suchbegriff nennen.

"range based for"

https://msdn.microsoft.com/en-us/library/...

// Hier darf sich der Kompiler den Datentype aussuchen, er wird den des Arrays nehmen

for (auto pin : myLedPins)  pinMode(pin, OUTPUT);

Ist vielleicht etwas unglücklich formuliert.

Mit auto ermittelt der Kompiler den genau passenden Typ.

Dann korrigiere es bitte in dem Zitat. Ich habe den Beitrag nicht schnell genug wieder raus genommen Du warst schneller im Zitieren, als ich beim löschen.

Also hier noch mal komplett, obwohl doch das gleiche, wie es unter deinem Link zu finden ist.

/*const*/ uint8_t myLedPins[] = { 10, 11, 12, 13 };

void setup() 
{

// pin wird als Referenz erzeugt, und darf im for Block nicht geändert werden
for (uint8_t const &pin : myLedPins)  pinMode(pin, OUTPUT);


// pin wird als value erzeugt, und darf im for Block nicht geändert werden
for (uint8_t const pin : myLedPins)  pinMode(pin, OUTPUT);


// pin wird als value erzeugt, und darf im for Block geändert werden
for (uint8_t  pin : myLedPins)
{
  pin++; // hat keine Auswirkung auf die Daten im Array
  pinMode(pin, OUTPUT);
}

// pin wird als Referenz erzeugt, und darf im for Block geändert werden
for (uint8_t  &pin : myLedPins)
{
  pin++; // Auch die Daten im Array werden geändert
  pinMode(pin, OUTPUT);
}


// Hier wird der Kompiler den Datentype des Arrays Elements verwenden
for (auto pin : myLedPins)  pinMode(pin, OUTPUT);


}

void loop() {}

Es ging mir nur um den Unterschied zwischen "aussuchen" und "ermitteln".

Whandall: Es ging mir nur um den Unterschied zwischen "aussuchen" und "ermitteln".

Ach, jetzt sei doch bitte nicht so pingelig.... Entspricht mein Kommentar jetzt deiner Messlatte?

Der Kompiler könnte auto durch jeden beliebigen, ihm bekannten, Datentype ersetzen. Er wird sich den aus dem Pool aussuchen, den auch die Arrayelemente haben. Nenne den Vorgang "ermitteln", wenn du magst.

combie:
Ach, jetzt sei doch bitte nicht so pingelig…

Ich werde weiterhin ein Freund von präzisen Ausdrücken bleiben.

combie:
Entspricht mein Kommentar jetzt deiner Messlatte?

// Hier wird der Kompiler den Datentype des Arrays Elements verwenen

Ich hätte noch Vorschläge bezüglich der Rechtschreibung, aber das zu bemäkeln wäre pingelig.

So sehr ich deine fachliche Kompetenz schätze, so sehr stört mich manchmal deine pingelige Art.

Ich werde weiterhin ...

Und ich werde nicht mehr auf deine Pingeligkeiten reagieren.

combie: So sehr ich deine fachliche Kompetenz schätze, so sehr stört mich manchmal deine pingelige Art.

Zwischen beiden Eigenschaften gibt es Zusammenhänge. ;)

Warum so empfindlich?

"Ist vielleicht etwas unglücklich formuliert." ist doch wirklich kein Angriff.

Vielen Dank für Link und Beispiele!

Um mal von eurer Kabbelei abzulenken:
Ausgerechnet auf eine msdn - Referenz zu verweisen, könnte man eher bemäkeln.

Arduino ( avr-gcc ) hat nun mit microsoft c++ nicht viel zu tun, daher zur Abschreckung diesen cccReference Link aus dem hervorgeht, dass es diese Konstruktion schon seit C++ 11 gibt, und es längst nicht alles ist, was es in diesem Bereich gibt (bzw. geben wird).

Danke an combie für die umfangreiche Beispiel-Sammlung incl. auto
// Hier wird der Kompiler den Datentyp der Array-Elemente verwenden
[pingel] Das ist meiner Meinung nach so Deutsch wie möglich[/pingel]
Was sich der Compiler nun tatsächlich raussucht, und wie er das in den seiner Meinung nach optimalen Maschinencode umwandelt sind ja noch mehrere Fragen, die hier OT sind.

michael_x: // Hier wird der Kompiler den Datentyp der Array-Elemente verwenden

Dummer weise hat sich der Kommentar gerade als falsch erwiesen. (ich hoffe, dass man mir diesen Irrtum verzeihen kann)

Das Array Element ist vom Type uint8_t. Wenn man einen Fehler im for Block provoziert, meldet der Kompiler, dass er an der Stelle "unsigned char" verwendet. Was im Grunde auch logisch und durchaus richtig ist, nur eben nicht direkt ersichtlich.

uint8_t ist ein synonym von unsigned char.

Dein Kommentar ist nach wie vor richtig.

nur eben nicht direkt ersichtlich

Das stört mich auch anauto. Wenn man selber nicht weiss, was für ein Datentyp es ist, kann es zwar gut gehen, aber irgendwann (z.B. beim Verstehen einer Fehlermeldung) muss man sich doch drum kümmern.

autowiderspricht meinem Mantra: Das wichtigste sind die Datentypen

Obautooderauto& sollte man auch selber entscheiden :)

Einen Iterator-Template-Datentyp will man am liebsten nicht direkt sehen, das gebe ich zu.

auto widerspricht meinem Mantra: Das wichtigste sind die Datentypen

Es spart Codeduplikate ein, welche sich nur im Datentype unterscheiden. Vergleichbar mit Templates.

Eigentlich ist es wie bei allen Sprachmitteln. Geschickt platziert, sind sie eine echte Hilfe.

Übertreibt man den Einsatz, leidet die Lesbarkeit, und damit meist auch die Wartbarkeit.

Darum: Faulheit ist kein ausreichender Grund, für den Einsatz von auto.

Auto ist hauptsächlich dafür gedacht wenn man mit Containern und Templates arbeitet. Da ist es nicht immer sofort ersichtlich welchen Datentyp man genau hat und die Syntax sehr schnell sehr unleserlich

Siehe z.B: hier: http://www.acodersjourney.com/2016/02/c-11-auto/ Da ist auch ein Beispiel dabei das zeigt dass auto nicht immer den eigentlichen Datentyp versteckt

Zum eigentlichen Thema: allgemein und in vielen anderen Sprachen heißt das "for each"

Nochmals vielen Dank für die weiterführenden Links und Hinweise!

Serenifly: Zum eigentlichen Thema: allgemein und in vielen anderen Sprachen heißt das "for each"

Ja, unter dieser Bezeichnung ist es mir aus anderen Sprachen bekannt. Und wieder fügen sich einzelne Puzzlesteine zu einem größeren Ganzen. :) Besten Dank!