C++Guns – RoboBlog blogging the bot

14.03.2017

C++ Guns - Funktion return unterschiedliche lambda Funktionen

Filed under: Allgemein — Tags: — Thomas @ 06:03

Na sicher geht das. Zur Compilezeit wie auch zur Laufzeit.
Zur Compilezeit wäre if constexpr angebracht, aber das kann mein Compiler noch nicht. Mit Templates wär das wieder overload. Also nehm ich stink normales Funktion überladen mit Tags.


struct Add_tag {};
struct Mult_tag {};

auto func1(int x, Add_tag) {
    return [x](int y){ return x+y; };
}

auto func1(int x, Mult_tag) {
    return [x](int y){ return x*y; };
}

int main() {
    cout << func1(2, Mult_tag())(3) << "\n";
    return 0;
}

Zur Laufzeit fällt mir std::function ein. Mit den üblichen Performancefressern.


enum class Operator {ADD, MULT};

std::function func1(int x, Operator op) {
    switch(op) {
    case Operator::ADD:  return [x](int y){ return x+y; };
    case Operator::MULT: return [x](int y){ return x*y; };
    }
}

int main() {
    Operator op = Operator::MULT;
    cout << func1(2, op)(3) << "\n";
    return 0;
}

Hübsch? Naaah. Braucht man? Bisher nicht.

12.03.2017

Biologie++ - DNA / RNA / UNA

Filed under: Allgemein — Tags: — Thomas @ 18:03

Aus: On the repliaton of desoxyribonucleic acid (DNA) by M. Delbrück

The structure proposed by Watson and Crick consists of two polynucleotide chains wound helically around a common axis, tied together by hydrogen bounds between the purine and pyrimidine side chains.
These side chains of the two chains are aranged so that adenine is always matched with thymine and guanine with cytosine.
The sequence of bases along either chains is not subject to any restrictions, but once the sequence along on chain is given, the sequence along the other chain is completely determinded. This sequence, then, constitutes the genetic information, a linear message written in a four-symbol code. The duplex of the two chains contains the information in a twofold redundance. Each chain has a directional polarity because of the nonequivalence of the 3- and 5- positions through which each pentose is linked to the preceding and the following phosphate group in the chan. This polarity runs in opposite directions in the two chains of the duplex.

Und ein Übersetzungsversuch

The Struktor vorgeschlagen von Watson und Crick besteht aus zwei poly nukleotide Ketten welche sich spiralförmig um eine gemeinsame Achse winden. Sie sind zusammengebunden durch Wasserstoffbrücken zwischen der purine? und pyrimidine? Seitenketten.
Die Seitenketten von den beiten Ketten sind so angeordnet, dass Adenine immer passend zu Thymine und Guanine mit Cytosine angeordnet sind.
Die Sequenz von Basen von einer Kette ist keiner Beschränkung unterlegen, aber sobald die Sequnez entlang einer Kette festliegt, so ist die Sequenz der anderen Kette komplett festgelegt. Diese Sequenz stellt die genetische Information dar. Eine lineare Nachricht, geschrieben in ein vier Symbol Code.
??? zweifachen Redundance. Jede Kette hat eine Richtungspolarität weil 5- und 3- nicht equivalent sind. Die 5- und 3- Positionen durch welche jede pentose verbunden ist durch die vorangegangene und nächste Phosphategruppe in der Kette. Die beiden Ketten verlaufen in entgegengesetzen Richtungen.

Und ein wenig aus Wikipedia

Die Gene in der DNA enthalten die Information für die Herstellung der Ribonukleinsäuren (RNA, im Deutschen auch RNS). Eine wichtige Gruppe von RNA, die mRNA, enthält wiederum die Information für den Bau der Proteine (Eiweiße), welche für die biologische Entwicklung eines Lebewesens und den Stoffwechsel in der Zelle notwendig sind. Innerhalb der Protein-codierenden Gene legt die Abfolge der Basen die Abfolge der Aminosäuren des jeweiligen Proteins fest: Im genetischen Code stehen jeweils drei Basen für eine bestimmte Aminosäure.

DNA --Info--> RNA -| (message)mRNA --Info--> Proteine | (Base,Base,Base) -> Aminosäure
                   | (ribosomale) rRNA
                   | (transfer) tRNA

Es gibt noch UNA, unique nucleotide sequence. Eine Definition habe ich bei medical-dictionary gefunden:

unique DNA
DNA sequences that occur only once in the haploid genome

Ja, ein Stück DNA, dass es so nur einmal im Kochtopf gibt, damit beim Assemblieren der Gene nichts falsch verbunden wird.

11.03.2017

C++17 Guns - std::optional Part IV

Filed under: Allgemein — Tags: — Thomas @ 13:03

Der Übergang von cpl::optional nach std::optional ist schnell gemacht. Nur beim Zugriff ändert sich sichtlich etwas. Wir können operator*, operator->, value() oder value_or() nutzen. Das sieht alles nicht gut aus:


if(DMP and SMP) {
    if(fuzzyEqual(abs(DMP->point.z - SMP.value().point.z), schacht.tiefe) == false) {
        cout << "Redundante Information Schachttiefe vs DMP-SMP";
    }
}

Bei operator-> denkt man gleich an Pointer. Bisher war es aber immer operator. gewesen. Und der extra Umweg über value() ist auch too verbose. Wenn wir mehr Richtung funktionaler Programmierung denken, dann ergibt sich die Möglichkeit, den ekligen Zugriff in einer Funktion zu verstecken. Diese Funktion bekommt beide Punkte, und eine Funktion, was mit den Punkten gemacht werden soll.
Das könnte in etwa so aussehen:


template
void maybeBoth(const optional& x, const optional& y, Function func) {
    if(x and y) {
        func(*x, *y);
    }
}

maybeBoth(schacht.DMP(), schacht.SMP(),
    [&schacht](const Punkt& DMP, const Punkt& SMP) {
        if(fuzzyEqual(abs(DMP.point.z - SMP.point.z), schacht.tiefe) == false) {
             cout << "Redundante Information Schachttiefe vs DMP-SMP";
        }
    }
);

Hmm mit der Einrückung hab ich so meine Probleme. Jedenfalls wäre das die kürzeste Variante, denn der maybeBoth Ausdruck ist nur eine Zeile. Der komische Zugriff ist weg, dafür müssen wir eine Funktion, oder ein Lambda definieren. Welches wiederum ein Funktionskopf mit Parameter braucht. Das ist wieder sehr verbose... In anderen Sprachen ist die Syntax angeblich viel besser.
Hm es ist anders zu lesen. Ungewohnt. Funktional eben. Da steht kein if() mehr. Das "Wenn" steckt jetz in "maybeBoth". Aber maybe was? Dass schacht.DMP() ein optional zurück gibt, ist hier nicht ersichtlich. Die logische Verknüpfung, dass DMP UND SMP existieren müssen ist hier nicht ersichtlich. Sicher, man kann das in der Dokumentation so festhalten von maybeBoth() und nach einer weile hat man das drauf.
Aber für ein winziges Stück Code, was ich maximal schnell hinschreiben will (Zeit ist Lebenszeit), ist das doch nichts. Womöglich sollte ich "maybe" durch "if" ersetzen. Also ifBoth(DMP, SMP)? Oder ifBothExist(DMP, SMP) ? Sieht schon besser aus. Voll viel Arbeit...

Aber nochmal kurz zurück an den Anfang. Was gewinne ich dadurch? Dass T in cpl::optional default construktible sein muss? Hm. MUSS es das wirklich? Durch die Vererbung wäre das doch angebracht. Sicher funktioniert cpl::optional nicht bei final Klassen. Es ist eben keine generelle Lösung, sondern eine, die jeder schnell versteht und umsetzen kann.

Eine Sache bleibt noch aus. Was passiert, wenn ich neben DMP und SMP auch noch RAP und SA brauche? Und ich möchte nicht die Schleife in Schacht::x vier mal laufen lassen. In nur einer Schleife soll überprüft werden, ob alle geforderten Punkte existieren und auf einmal, alle als optional, zurück gegeben werden. Ob das gut funktioniert?

C++17 Guns - std::optional Part III

Filed under: Allgemein — Tags: — Thomas @ 12:03

So, kommen wir zum dritten Teil. Zu Versuchs und Lernzwecken habe ich meine eigene cpl::optional Klasse geschrieben, die genau das macht, was ich zur Zeit brauche. Ich mache mir absichtlich das Leben einfach und vordere, dass der Typ default constructible sein muss. Hält cpl::optional kein Wert, so ist ein default Wert gespeichert. Das hat die schon beschriebenen Nachteile, aber man muss ja pragmatisch denken. Die Syntax soll nicht so einfach wie möglich sein, sondern so einfach, wie sie vorher schon war. Zum Vergleich zeige ich den alten Code, eine funktionale Version und eine neue Version

Alter Code:


    bool hasDMP = false;
    Punkt DMP;
    bool hasSMP = false;
    Punkt SMP;
    for(const Punkt& punkt : schacht.punkte) {
        if(punkt.attr == PunktAttributAbwasser::DMP) {
            hasDMP = true;
            DMP = punkt;
        } else if(punkt.attr == PunktAttributAbwasser::SMP) {
            hasSMP = true;
            SMP = punkt;
        }
    }

    if(hasDMP and hasSMP) {
        if(fuzzyCompare(abs(DMP.point.z-SMP.point.z), schacht.tiefe) == false) {
            cout << "Redundante Information Schachttiefe vs DMP-SMP";
        }
    }

Diese Version hat folgende Nachteile und sleeping errors (Phew wo fang ich denn an).
a) WAS vs. WIE. In dem Code steht, WIE die zwei Punkte gefunden werden und danach WIE damit weiter verfahren wird. Aber es steht nicht da WAS überhaupt gemacht werden soll.
b) SMP und DMP sind ähnlich geschriebene Variablen die leicht verwechselt werden können. Das sind aber vorgegebene Abkürzungen die es einzuhalten gilt. Viel schlimmer aber sind die beiden zusätzlichen bool Variablen. Es können die bool und Punkt Variablen in jeder Kombination vertauscht werden.
c) Die Lebenszeit der DMP und SMP Variablen ist zu lange. Nach der letzten if() geht der Code normalerweise noch weiter. Hier könnte man eine der Variablen wieder benutzen, obwohl das gar nicht beabsichtigt ist. Ein ähnliches Problem hat die Sprache C mit der Laufvariable i in for() Schleifen. Das ist seit 1984 in C++ nie wieder ein Fehler gewesen.
d) RAII nicht beachtet. Erst wird der Punkt default initialisiert, und später vllt. einem anderen Punkt aus dem Schacht zugewiesen. Statt gleich die Zuweisung zu machen.
e) Und letztendlich wird eine Kopie des Punktes erzeugt. Das ist in diesem Fall aber das kleinere Übel. Referenzen, Indices, Iteratoren oder Pointer können alle invalid werden, sollte sich die Punkte in dem Schacht zwischenzeitlich ändern.

Hier sind Lösungsvorschläge:
a) Die Schleife muss in eine Funktion ausgelagert werden.
b) Punkt und bool Variable in ein neuen Datentyp koppeln.
c) Mehrere Möglichkeiten:
Scope durch zwei Klammern {} verkleinern.
Code in eine weitere Funktion packen.
C++17 "Selection statements with initializer" nutzen.
d) Auch (teil)gelöst durch Schleife in Subroutine.

Punkt a) ist trivial. Das sollte etwa so aussehen: auto DMP = punkt.DMP();
Punkt b) ist durch ein optional lösbar. Ich zeige Code mit std::optional und cpl::optional.
Punkt c) C++17 ist natürlich vorzuziehen.
Punkt d) Da cpl::optional default constructible brauchst ist hier RAII nicht so zu 100% enigehalten.

Fangen wir an:


cpl::optional<Punkt> Schacht::DMP() const {
    for(const Punkt& punkt : punkte) {
        if(punkt.attr == PunktAttributAbwasser::DMP) {
            return punkt;
        }
    }

    return {};
}

Im Erfolgsfall wird der Punkt zurück gegeben, sonst ein default cpl::optional, welches keine Daten hält. Für SMP() analog. Um zu testen ob ein std::optional ein Wert hält, gibt es die Funktionen has_value() oder operator bool. Ich möchte gern die Funktion beim Namen nennen, um den Code lesbarer zu halten. Aber punkt.has_value() ist.. seltsam. Jeder Punkt hat doch Werte? Daher nehme ich für cpl::optional lieber den Funktionsnamen exist(). Und so schauts aus:


auto DMP = schacht.DMP();
auto SMP = schacht.SMP();

if(DMP.exist() and SMP.exist()) {
    if(fuzzyCompare(std::abs(DMP.point.z-SMP.point.z), schacht.tiefe) == false) {
        cout << "Redundante Information Schachttiefe vs DMP-SMP";
    }
}

Das ist schon wesentlich lesbarer. Hier empfiehlt sich die NUtzung von "auto", sonst müsste man umständlich cpl::optional schreiben. Also, Punkt a) b) d) erfüllt. Für c) nehme ich C++17, das sieht dann so aus:


if(auto DMP = schacht.DMP();  DMP.exist()) {
    if(auto SMP = schacht.SMP(); SMP.exist()) {
        if(fuzzyEqual(std::abs(DMP.point.z-SMP.point.z), schacht.tiefe) == false) {
            std::cout << "Redundante Information Schachttiefe vs DMP-SMP";
        }
    }
}

Jetzt bin ich mir nur nicht sicher, ob die Initialisierung in der if() auch für mehrere Variablen funktioniert, oder ob der Compiler noch buggy ist. Aber jedenfalls, aus den anfänglichen 19 Zeilen Code sind es 7-8 geworden. Ein WIE wurde in ein WAS verwandelt. Der zweite Teil mit dem fuzzyEqual lass ich mal so stehen.

Hier die Implementierung von cpl::optional


namespace cpl {
template<class T>
struct optional : public T {
    static_assert(is_default_constructible<T>::value);
    optional() = default;

    optional(const T& t)
        : T(t), vorhanden(true)
    {

    }

    explicit operator bool() const {
        return vorhanden;
    }

    bool exist() const {
        return vorhanden;
    }

    bool vorhanden = false;
};
}

Das nächstemal geht es mit std::optional weiter

10.03.2017

C++17 Guns - std::optional Part II

Filed under: Allgemein — Tags: — Thomas @ 11:03

Wie schon im ersten Teil berichtet, suche ich vernünftige Anwendungsfälle für std::optional.
Dabei ist mir aufgefallen, dass schon viele Variablen implizit optional sind/behandelt werden. Ohne, dass eine extra Variable wie z.B. bool vorhanden; vorhanden ist. Nehmen wir z.B. ein Adressbuch. Wenn der Adresszusatz nicht angegeben wurde, ist der String einfach leer. Ein std::optional<std::string>> adresszusatz; wäre redundante Information. Einmal explizit im std::optional und einmal implizit im string::size.

Bei Strings ist das einfach. Doch was ist mit Zahlen? Wenn die Hausnummer in der Adresse als Integer gespeichert wäre, und es fehlt die Information, welche Zahl ist in der Variablen hausnummer dann gespeichert? int hausnummer = 0; Null als Default? Oder lieber -1? Oder Undefiniert? Oder MAX/MIN Integer Wert? Bei floats gäbe es NaN...

Die Idee ist, dass Zahlen einen validen Wertebereich haben. Negative Hausnummern gibt es einfach nicht. Auch ist es sehr unwahrscheinlich, dass eine Straße zwei Milliarden Häuser hat. Die Information, ob der Wert vorhanden ist, oder nicht, ist im Wert selbst kodiert. Das widerspricht aber dem C++ Ziel, eine generalisierte Sprache zu sein. Die allgemeingültige Lösung für std::optional kann daher nicht so implementiert sein, dass die 'vorhanden' oder 'nicht vorhanden' Information in der eigentlichen Variablen mit gespeichert wird.

Wir würde eine Implementation von "optional" aussehen?
Eine zusätzliche boolean Variable bool vorhanden = false; wäre denkbar. Aber das kleine bool verhunzt das Speicherlayout der Klasse. Man könnte nur einen Pointer nehmen. Ein nullptr bedeutet, dass der Wert nicht vorhanden ist. Aber dann haben wir das owning Problem wie mit dem std::shared_ptr auch. Was ist, wenn std::optional eine Kopie der Variable hält? Problem 1 gelöst. Problem 2: Welcher Wert hat denn das optional, wenn es kein Wert gibt? Ein default Wert. Welcher? Nicht jede Klasse hat einen default ctor oder kann überhaupt einen haben.

Ich sehe, default Werte, default ctors und std::optional und string::size (vector::size) haben viel gemeinsam. Da kommt auch gleich die RAII (Ressourcenbelegung ist Initialisierung) Idee daher. Man schreibt nicht einfach std::string s; int i; oder int i=0; Sondern belegt die Variable gleich mit einem gültigen Wert.
std::string s = func(); int i = func(); Was aber, wenn func() keinen Wert zurück liefern kann, weil es keinen gibt? Das muss nicht gleich ein Fehler sein. Datensätze sind nunmal nie vollständig. Das ist das selbe Problem wie oben besprochen.

Ich persönlich fühle mich nicht wohl mit dem Gedanken, überall im Code optionals zu haben, die existieren könnten, oder nicht. Die Variationen gehen exponentiell mit der Anzahl der Variablen. Das will niemand und ich bezweifle, dass man das überhaupt braucht.

Also mir kommen da zwei Möglichkeiten in den Sinn. Der Erste, wie oben schon angedeutet, einen gültigen Wertebereich definieren. Viele Variablen bilden ja irgendwas aus der Realität ab. Z.B. eine Höhenangabe auf der Welt. Was ist der höchste Punkt? Irgendwas mit 8000m. Was ist der tiefste Punkt? Irgendwas mit -11000m. Man kann also eine noDepthValue definieren mit -99999m und ihn als default Wert für Höhenangaben nutzen. Das lässt sich mit dem Typesystem auch leicht implementieren. using Height_t = double; Oder beliebig kompliziert. Das Funktioniert mit Koordinaten genauso. Im sphärischen System gibt es keinen Rechtswert größer als 180grad. Vorraussetzung dafür ist, dass das "Ding" in der Realität auch genau diesen Typ in C++ bekommt. Also kein double x; mehr. Lieber Coordinate x; So können auch gleich SI Einheiten mit einbezogen werden. Aber das ist ein anderes Thema. Das ist auch gleich Performant und SSE freut sich, wenn die Daten alignt rein kommen.

Ist die erste Möglichkeit schon sehr Domänenspeziell, brauchen wir auch eine allgemeingültige C++ Philosophie Lösung. Hier orientiere ich mich an std::string::size bzw std::vector::size. Wie schon oben Erwähnt, ist die Information, ob ein String leer ist oder nicht, in der size Variable in der std::string Klasse abgelegt. (Und nicht, wie bei C, im den eigentlichen String Daten selbst). Was hindert mich daran, das für alle anderen Daten auch zu tun? Für das Beispiel nehme ich nochmal die Adresse.


struct Name {
  string vorname, nachname;
};
struct Adresse {
  vector<Name> name;
  vector<string> strasse;
  vector<int> hausnummer;
  vector<string> stadt;
};

Na, ist das nichts? ;) Ich finde das sehr realistisch. Hat die Adresse keinen hausnummer, so ist der vector einfach leer. Ein leerer Vector führt bei keiner Library zu Problemen. Jede for() Schleife ist glücklich damit. Da steckt das if(vorhanden) schon drin. Und wer sagt denn bitte schön, dass eine Person nur einen Namen haben darf? Wenn man heiratet, ändert sich der Nachname. Wenn man die Identität wechselt, ändert sich der Name. Die Freunde nennen einem meist nicht beim vollen Namen. Im Internet hat man Nicks. Man kann sich auch als jemand anderes ausgeben. In anderen Ländern wird sein Name womöglich leicht anders geschrieben und ausgesprochen. Soll ich weiter machen? Das selbe gilt natürlich auch für die restlichen Variablen. Hier wäre also sogar ein Zeitfaktor mit implementiert ;)
Absolut übertrieben und Anwendungsfern? Ja aber, genau das wollen wir doch mit c++.

09.03.2017

Biologie++ - Über die Natur der Genmutation

Filed under: Allgemein — Tags: — Thomas @ 20:03

Eine kurze Zusammenfassung der Zusammenfassung von "Über die Natur der Genmutation und der Genstruktur" von Max Delbrück, Timofeeff-Ressovsky und K.G. Zimmer.

a) Spontan treten verschiedenste Mutationen auf, die Mutationsrate ist aber gering, und beträgt ... ca. 0.1%
b) Die spontane Mutabilität ist zeitunabhängig...
c) Die spontane Mutationsrate ist als Prozentstatz der Mutationen pro Zeiteinheit zu definieren.
d) Die spontane Mutationsrate ist temperaturabhängig und folgt der CAN T'Hoff'schen Regel...
e) Verschiedene Gene, und auch verschiedene Allele desselben Gens zeigen verschieden ohne Mutationsraten...
f) Durch Röntgen ... -strahlung wird die Mutationsrate stark erhöht. ...
g) Die Bestrahlung ruft bei beiden Geschlechtern und in verschiedenen Geweben Mutationen durch direkte Beeinflussung der Gene ... hervor. ...
h) Die durch Bestrahlung ausgelöste Mutationsraten sind den applizierten Dosen direkt und linear proportional.
i) Von der Wellenlänge ... der applizierten Strahlung ist weder die Halbwerstdosis, noch die Form der Proportionalitätskurve der Mutabilität abhängig. ...
k) ... Die Mutationsrate ist ... zeitfaktorunabhängig und hängt nur von der Gesamtmenge der applitierten Strahlung.
l) Die mutationsauslösende Wirkung der Strahlung ist von der Temperatur ... unabhängig. ...
m) Die strahleninduzierte Rate einzelner Gene wird anscheinend, ..., von der Struktur der bet. Allel mitbeeinflußt. ...
n ) Die spontan besonders labilen Gene brauchen keine entsprechende, besonders hohe strahleninduzierte Mutationsrate zu ergeben.
o) Bei den "mutablen" Allen ist der Einfluß der Temperaturerhöhung und der Bestrahlung auf die Mutationsrate minimal.

Vierter Teil: Theorie der Genmutation und der Genstruktur

...
Die Mutation wird durch Zufuhr der Energie von außen oder durch Schwankungen der Temperaturenergie, die unvermeidlich mit der statisch-linetischen Natur der Wärme verbunden ist, erzeugt, und besteht in einer Umlagerung der Atome in eine andere Gleichgewichtslage innerhalb eines Atomverbandes. Als Atomverband wird dabei eine Struktur definiert, in der bestimme Atome in bestimmter Lage stabil angeordner sind.
...

C++(+)

Filed under: Allgemein — Tags: — Thomas @ 18:03

"c++17 is out now."
"c++20 we know if you think on macros. people will die if you dont stop it"
"c++30 alle pepole who has written code in FORTRAN77 are dead now"
"c++35 there are only 10 kinds of languages out there. strong types and not"
"c++36 only strong types left"
"c++42, this is the answer. what was the question?"
"c++64 good damn this is an old language. huh? you are right $/§. did you remeber c++32? oh yeah that was fun. swap it. what would you get? 23!!aaaargghl"

Biologie++ - Einführung

Filed under: Allgemein — Tags: — Thomas @ 18:03

Zum Start möchte ich mit einem Zitat von 1933 beginnen. Der Gedanke ist von Nils Bohr. Aus den Erinnerung von Max Delbrück. Niedergeschrieben von Ernst Fischer. Zu lesen in "Das Atom der Biologen".

In der Physik kennt man das einfachste Atom, den Wasserstoff. Ein Elektron umkreist ein Proton. Man kann nun bis zum Ende aller Tage damit klassische Physik betreiben, es wird doch niemals ein stabiles Atom werden. Erst wenn man das Quantum der Wirkung einführt und komplementär denkt, versteht man die Wirklichkeit in diesem Bereich. In der Biologie stelle man sich die einfachste Form des Lebens vor, zum Beispiel eine Zelle. Man weiß, sie besteht aus den Molekülen und anderen Elementen der organischen Chemie. Man kann nun wieder das Zusammenwirken aller dieser Komponenten bis in alle Ewigkeit analysieren und beschreiben, es kommt nichts Lebendes dabei heraus, es sei denn, man denkt komplementär und fügt etwas hinzu, was analog zum Wirkungsquantum der Atome ist.

Max Delbrück hat bis zum Lebensende nach dieser komplementäre Sache gesucht, aber nicht gefunden. Ob so etwas mittlerweile gefunden wurde?
Als eine der bedeutendsten Entdeckungen zu jener Zeit gehört die Doppelhelix der DNA. Jene, und RNA, lassen sich hervorragen im Computer abbilden und zur Simulation nutzen.
Max Delbrück hat mit Timofeeff-Ressovsky und K.G. Zimmer in der Arbeit D8, "Über die Natur der Genmutation und der Genstruktur", gezeigt, "dass stabile Gene mit steigender Temperatur labiler werden, während die ursprünglichen leicht anfälligen Gene dadurch unbeeinflußt bleiben - genau dies beobachtete man im Experiment".

Lasst uns damit anfangen...

C++17 Guns - std::optional

Filed under: Allgemein — Tags: — Thomas @ 13:03

Ich glaube, ich sehe einen Verwendungszweck für std::optional.
Ein hydraulischer Schacht kann mehrere Punkte besitzen. Z.B. für Schachtdeckel (DMP) und Schachtmittelpunkt (SMP). Nun sind Datensätze nie vollständig, und ich muss mit beiden Punkthöhen weiter rechnen, wenn sie denn existieren. Das lässt sich natürlich leicht über ein boolean hasDMP realisieren. Und einer Schleife die über alle Punkte läuft. Natürlich will niemand im Code 100x die selbe Schleife schreiben. Es würde auch dem "WAS und nicht WIE" Prinzip widersprechen. Also wird die Schleife in eine Funktion ausgelagert. Die Schleife gibt den Punkt zurück und ein boolen, ob der Punkt auch existiert.


auto [DMP, hasDMP] = schacht.DMPpunkt();
auto [SMP, hasSMP] = schacht.SMPpunkt();
if(hasDMP and hasSMP) {
    distanceTo(DMP, SMP);
}

Ist ganz nett, und durch das "auto" auch relativ kurzer Code. Aber es geht mit std::optional wohl noch kürzer. Möglicherweise so:


auto DMP = schacht.DMPpunkt();
auto SMP = schacht.SMPpunkt();
if(DMP and SMP) {
    distanceTo(DMP, SMP);
}

Ist hier die Semantik zu abstrakt? Ist intuitiv klar was if(DMP) bedeutet? Der Typ der DMP und SMP Variabel ist schon variabel. Das ist schon brainfuck für viele C++ Programmierer aber lustigerweise Schokolade für die Python Programmierer. Aber jetzt ist sogar die Existenz der Variabel variabel.

Und wie sieht es mit der Performance aus? Kann std::optional so implementiert werden, dass kein new() aufgerufen wird?

Nachteil: Höhere Laufzeit, da zwei mal die Schleife gestartet wird. Vorschlag: tupel Schacht::punkte(Args...) Hm?

C++17 Guns - std::make_tuple - warum so umständlich?

Filed under: Allgemein — Tags: — Thomas @ 11:03

Seit C++11 gibt es den Typ std::tuple und std::pair. Das erstellen derselben war über Hilfsfunktionen std::make_tuple() bzw. std::make_pair() möglich:


auto x = std::make_tuple(1, 'X', 3.14);

Die Vereinfachung wurde jetzt im C++17 Standard aufgenommen. Nennt sich P0091R3 - Template argument deduction for class templates.

This paper proposes extending template argument deduction for functions to constructors of template classes

GCC unterstützt es seit Version 7. Damit ist der obige Code nun intuitiver wie folgt zu schreiben:


auto x = std::tuple(1, 'X', 3.14);

Die Sprache wird immer einfacher...

« Newer PostsOlder Posts »

Powered by WordPress