Hi,
On 02/05/2022 21:58, Jeffrey Kelling wrote:
make
g++ -c -o src/lib/init_hw.o src/lib/init_hw.cpp src/lib/init_hw.cpp:In member function ‘void ZEROHW::init_hw(const std::vector<std::__cxx11::basic_string<char> >&)’: src/lib/init_hw.cpp:52:69:error: use of ‘auto READCSV::read_config_files(const string&)’ before deduction of ‘auto’ 52 | auto pin_defs = read_csv.read_config_files(file_names[0]); | ^ make: *** [<eingebaut>: src/lib/init_hw.o] Fehler 1
Hast du vllt die Funktion mit `auto` Rückgabetyp in einem Header nur deklariert, aber nicht definiert? `auto` geht nur, wenn der Compiler beim Aufruf auch sieht was in der Funktion zurückgegeben wird, wenn sie als auf irgendeineweise inline bzw. in der gleichen Kompiliereinheit definiert wird. Wenn die Definition in einer separaten Einiheit ist, dann musst du explizit sagen was der Rückgabetyp ist, also `std::vector<csv_values>`.
Noch ein kleiner Nachschlag dazu: auto ist eines der praktischsten Features in C++-11, aber wie immer in C++ kann/sollte man es nicht immer und überall einsetzen.
Wann man auto unbedingt einsetzen sollte:
Wenn man einen numerischen Typ von einer Funktion zurückbekommt: auto zahl = meineFunktion(); Das verhindert dass man den falschen Typ für "zahl" deklariert und ein automatischer Cast den Wertebereich kaputt macht (beliebt sind "int" und "sizeof" auf 64-bit Maschinen).
Als Rückgabetyp wenn man Templates definiert (Profi-Tip: wenn Du innerhalb der ersten 5 Jahre C++ ein Template definierst, dann machst Du wahrscheinlich was falsch; Templates benutzen ist dagegen okay, gewünscht und sogar hilfreich).
Bei komplexen Operationen bei denen es nicht intuitiv ist was der Ergebnistyp ist: auto ergebnis = getMyCollection().at(42).transform(otherGadget).last();
Wan man NICHT auto einsetzen sollte:
Wenn man selbst Funktionen/Methoden deklariert, es sei denn es ist eine triviale inline-Funktion. Also alles was komplexer als "inline auto square(int a){return a*a;}" ist sollte seinen Typ explizit deklarieren. Sprich: wenn die Definition der Funktion inline im Header steht und auf eine Zeile passt, dann auto, sonst explizit.
Wenn man weiß dass mit Referenzen oder Pointern herumhantiert wird und man den Wert weitergeben oder aufheben will, dann ist es einfacher explizit zu sagen welcher nicht-Referenz-Typ es sein soll.
In der Parameterliste von Funktionen bringt es nur unverständliche Fehlermeldungen. ;-)
Vorsicht bei der Initialisierung von Member-Variablen: auto mysize=5; ist wahrscheinlich nicht so gewollt - es erzeugt eine int Variable, aber "size" sollte lieber size_t, ssize_t oder long sein...
Für alle anderen Fälle gilt:
Wenn eine Ergebnis-Variable auto-Typing bekommt hilft es im Allgemeinen Verwirrung zu vermeiden, aber es gibt Ausnahmen.
Wo wir gerade bei Vereinfachungen und Hinweisen sind:
* deklariere so viel wie möglich const - dann sagt Dir der Compiler wenn Du ausversehen irgendwo schreibst wo Du es nicht solltest, z.B. if(a=3)... * bei großen Datentypen (string, array, vector, ...): deklariere Funktionsparameter als const-Referenz (geht schneller), Rückgabe-Typen als non-Referenz (crasht sonst gerne mal); merke Dir niemals eine Referenz, sondern mach' Kopien * wenn Du schon Pointer benutzt, dann initialisiere sie auf nullptr und setze sie nach delete auch immer auf nullptr zurück - das macht die Fehlerdiagnose einfacher! * wenn Du eine Referenz zurückgibst machst Du zu 99% einen Fehler, das verbleibende 1% ist zum größten Teil schon von der STL abgedeckt * Pointer sind Teufelswerk; Referenzen sind besser aber nicht ganz ungefährlich(*); Value-Typen sind fett und langsam - wähle Dein Gift vorsichtig ;-) * Optimiere erst wenn Du merkst dass es nötig ist, nicht schon wenn Du glaubst cleverer zu sein als Dein Computer (moderne Compiler sind Wunderwerke der Technik) * C-Strings sind okay um std::string zu initialisieren (z.B. std::string s="Hallo Welt"), aber sonst sollten sie vermieden werden. * Kommentare sind gesund, erhöhen die Biodiversität im Code-Dschungel und sollten gut gepflegt werden. Fehlende Kommentare führen zu tragischen Code-Verlusten.
(*)Apropos Referenzen:
* Referenzen auf globale Variablen sind okay, aber eigentlich sollte man globale Werte vermeiden * Referenzen auf statische Klassen-Variablen sind okay und besser als ganz globale Werte * Referenzen auf Variablen in main() sind meistens okay, können aber schiefgehen wenn sie in im Exit-Handler benutzt werden (z.B. im Destruktor einer globalen Variable, ja der wird aufgerufen!) * Referenzen auf lokale Werte sollte man vermeiden - es ist okay sie in einen tieferen Stack-Frame zu geben, solange der sich die Referenz nicht merkt * Referenzen auf Werte aus einem tieferen Stack-Frame sind lebensgefährlich, weil der Speicher entweder schon freigegeben ist oder Unsinn enthält * Referenzen, die von einer Funktion zurückgegeben werden sollte man nur auf der selben Zeile verwenden und dann vergessen, wenn Du es länger brauchst mach eine Kopie * Nimm niemals an dass eine Referenz aus einem Parameter länger lebt als die aktuelle Funktion!
Konrad