Im Beispielcode für Bluetooth LE mit einem Arduino Nano 33 BLE heißt es
:
1
BLEDeviceperipheral=BLE.available();
2
3
if(peripheral){
4
Serial.print("Found ");
5
}
Wobei "peripheral" doch wohl ein Objekt der Klasse "BLEDevice" ist. Bei
Stackoverflow ist man sich einig, dass man Objekte nicht null setzen
kann. Was überprüft also das if im Beispiel ?
Ich würde nämlich gerne an einer Stelle in meinem Programm "peripheral"
auf etwas setzen, so dass die Bedingung falsch ist.
Wie kann ich das machen ?
Wie ist BLEDevice denn definiert?
Wenn es ein Zeiger ist, wird der im if auf ungleich NULL geprüft.
Ansonsten kann man sich in C++ für jeden Datentyp eine Konversion nach
bool definieren und damit ein Objekt auf true oder false testen (z.B.
Iteratoren, smart pointer, optional<> etc.).
FOp schrieb:> Wobei "peripheral" doch wohl ein Objekt der Klasse "BLEDevice" ist. Bei> Stackoverflow ist man sich einig, dass man Objekte nicht null setzen> kann.
Wo steht das?
Bei stackoverflow laufen ganz clevere Leute rum.
Ich glaube kaum, daß so eine pauschale und in ihrer Pauschalität
unrichtige Aussage dort so steht.
Klaus W. schrieb:> und in ihrer Pauschalität> unrichtige Aussage dort so steht.
Denke doch, dass das stimmt....
Pointer kann man auf NULL oder nullptr setzen, aber keine Instanzen.
Klaus W. schrieb:> Ansonsten kann man sich in C++ für jeden Datentyp eine Konversion nach> bool definieren und damit ein Objekt auf true oder false testen
So ist es!
Klasse::operator bool() {return istNebelig();}
EAF schrieb:> Pointer kann man auf NULL oder nullptr setzen, aber keine Instanzen.
Nicht im Sinne von Java, sodaß das Objekt tatsächlich ungültig ist.
Aber man kann sich einen (logisch) ungültigen Zustand definieren, z.B.
in einer bool.Memervariablen und z.B. mit einem operator entsprechend
setzen.
Siehe die diversen smart-Pointer oder std::optional<>.
Meistens führt eine Initialisierung mit dem default constructor bei
einem Aufruf von "operator bool()" zu false (wenn einer vorhanden ist).
So auch hier (laut link von Tom).
Also:
Klaus W. schrieb:> Aber man kann sich einen (logisch) ungültigen Zustand definieren, z.B.> in einer bool.Memervariablen und z.B. mit einem operator entsprechend> setzen.
Natürlich.
Wäre ja auch eine armselige OOP Implementierung, wenn ein Objekt keine
inneren Zustände halten könnte.
Das wird auch bei Stackoverflow sicherlich niemand bezweifeln.
Ist also eine ganz andere Baustelle.
Ansosnten:
Die Frage war, wie if (peripheral) da oben funktioniert, und die hast du
richtig beantwortet.
W.A. schrieb:> Das wird dir verraten, ob es dein Objekt gibt
Falsch!
Wenn der eben genannte Operator nicht definiert wird, ist eine Instanz
immer true. Ohne jede Alternative. Denn die Instanz MUSS existieren.
Mikro 7. schrieb:> operator bool
Es gibt keinen operator bool.
Aber es gibt einen Operator, welcher beim Konvertieren verwendet wird.
"Konvertierungsoperator" wäre als oder etwas bessere Begriff.
Schlussendlich kann die betreffende Klasse selber entscheiden WIE sie
konvertiert wird.
Mikro 7. schrieb:> imho
Eigentlich ein übliches Verfahren in C++.
Es wundert mich, dass du das nicht kennst.
Minus M. schrieb:> Mikro 7. schrieb:>> BLEDevice::operator bool() const>> Und> Zwiebelkuchen Klasse::operator Zwiebelkuchen() const .....> ist dann ein Zwiebelkuchen operator?> Nee...
Nein! Es ist operator Zwiebelkuchen. Es ist ja auch operator bool und
nicht bool operator ...
EAF schrieb:> Mikro 7. schrieb:>> imho> Eigentlich ein übliches Verfahren in C++.> Es wundert mich, dass du das nicht kennst.
Was genau meinst du mit "üblich"?
Mombert H. schrieb:> Was genau meinst du mit "üblich"?
"üblich" heißt weit verbreitet, Normalität.
Der Default wäre wohl:
BLEDevice::operator bool() {return true;}
Abschaltbar, in der Klassendefinition, mit
operator bool() = delete;
Das überladen von Operatoren und Methoden ist eine gut dokumentierte
C++ Spracheigenschaft.
Der Casting Operator ist da keine Besonderheit.
Damit eigentlich auch kein Grund sich zu wundern.
Mombert H. schrieb:> Nein! Es ist operator Zwiebelkuchen. Es ist ja auch operator bool und> nicht bool operator ...
Hach...
Es ist der Konvertierungs Operator.
Einmal kann er nach Zwiebelkuchen konvertieren und einmal nach bool.
Dass es schon eine vorgefertigte Implementierung gibt, tut dabei nix zur
Sache, denn er wird überschrieben, falls es ihn schon gibt..
So wie auch string den Operator = überschreibt, oder zumindest überläd.
EAF schrieb:> W.A. schrieb:>> Das wird dir verraten, ob es dein Objekt gibt>> Falsch!> Wenn der eben genannte Operator nicht definiert wird, ist eine Instanz> immer true.
Um dich zu zitieren:
> Falsch!
Wenn der Operator nicht definiert ist, bricht der Compiler mit einem
Fehler ab, da if einen booleschen Wert fordert, das Objekt aber keiner
ist und dann eben mangels Operator auch nicht in einen konvertiert
werden kann.
Rolf M. schrieb:> Wenn der Operator nicht definiert ist, bricht der Compiler mit einem> Fehler ab, da if einen booleschen Wert fordert, das Objekt aber keiner> ist und dann eben mangels Operator auch nicht in einen konvertiert> werden kann.
Stimmt!
Du hast war.
Ich nehme den Default zurück.
Ein Irrtum meinerseits.
Das "üblich" allerdings nicht.
EAF schrieb:> Mombert H. schrieb:>> Was genau meinst du mit "üblich"?>> "üblich" heißt weit verbreitet, Normalität.
Dann bewegst du dich in anderen C++ Kreisen als ich. Wenn eine
Konvertierung nötig ist, erfolgt das normalerweise über einen
entsprechenden explicit Konstruktor.
> Der Default wäre wohl:> BLEDevice::operator bool() {return true;}>> Abschaltbar, in der Klassendefinition, mit> operator bool() = delete;
Default? Abschaltbar? Was meinst du damit?
> Das überladen von Operatoren und Methoden ist eine gut dokumentierte> C++ Spracheigenschaft.> Der Casting Operator ist da keine Besonderheit.> Damit eigentlich auch kein Grund sich zu wundern.
Es gibt meiner Meinung nach nur sehr sehr selten einen guten Grund
diesen Operator zu implementieren.
> Ich bin mir nicht sicher, ob die Existenz, die Semantik oder die> Implementierung schlimmer ist.
Für sich alleine genommen sind sowohl Existenz, Semantik als auch
Implementierung in Ordnung.
Das Problem ist, nach 40 Jahren haben sich tausende von Features und
Designpattern angesammelt, die eigentlich alle ok sind. Aber wie dieser
Thread zeigt - es sind zu viele. Jeder C++ Programmierer kennt und
benutzt unterschiedliche Teile der Features und Pattern.
Mombert H. schrieb:> Default? Abschaltbar? Was meinst du damit?
Nix default!
Das war ein Irrtum.
Default/Dokumentierte Konvertierungen gibt es nur für die mitgelieferten
Datentypen, wie z.B. alle Integer, Pointer
Abschaltbar: delete
Ohne operator bool() {return true;}
> error: could not convert 'test' from 'BLEDevice' to 'bool'
Mit operator bool() = delete;
> error: use of deleted function 'BLEDevice::operator bool()'Mombert H. schrieb:> Dann bewegst du dich in anderen C++ Kreisen als ich
Möglich.
Rolf M. schrieb:> Mombert H. schrieb:>>> "üblich" heißt weit verbreitet, Normalität.>> Dann bewegst du dich in anderen C++ Kreisen als ich. Wenn eine>> Konvertierung nötig ist, erfolgt das normalerweise über einen>> entsprechenden explicit Konstruktor.>> Man kann keine Konstruktoren für bool schreiben.
Es gibt auch selten einen guten Grund implizit nach bool zu
konvertieren.
>> Es gibt meiner Meinung nach nur sehr sehr selten einen guten Grund>> diesen Operator zu implementieren.>> Das gibt es schon in der Standardbibliothek häufiger:> https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool> https://en.cppreference.com/w/cpp/utility/functional/function/operator_bool> https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool> https://en.cppreference.com/w/cpp/utility/optional/operator_bool> https://en.cppreference.com/w/cpp/error/error_code/operator_bool
Und bei welchem dieser Beispiele ist die Bedeutung dieser Konvertierung
nach bool offensichtlich? Was der Wahrheitswert eines basic_ios? Was ist
der Wahrheitswert eines shared_ptr? Was ist der Wahrheitswert eines
shared_ptr<bool*>? Was ist der Wahrheitswert eines std::optional<bool>?
Ich kann bei keinem, der von dir gelisteten Typen, die Frage "Was ist
der Wahrheitswehrt von X?" beantworten.
Noch ein Kommentar schrieb:>> Ich bin mir nicht sicher, ob die Existenz, die Semantik oder die>> Implementierung schlimmer ist.>> Für sich alleine genommen sind sowohl Existenz, Semantik als auch> Implementierung in Ordnung.
Echt? Wie kann es in Ordnung sein, dass der Wahrheitswert eines
Bluetooth-Devices mit seiner Adresse zu tun hat? Und wie kann es in
Ordnung sein, dass in C++ die Adresse mit memcpy verglichen wird?
Mombert H. schrieb:> Echt? Wie kann es in Ordnung sein, dass der Wahrheitswert eines> Bluetooth-Devices mit seiner Adresse zu tun hat? Und wie kann es in> Ordnung sein, dass in C++ die Adresse mit memcpy verglichen wird?
Naja....
Vielleicht, weil es der Programmierer so definiert hat?
Weil es zum Interface der Klasse gehört?
Und hoffentlich dokumentiert ist.
Es ist völlig ok, wenn dir das Verfahren nicht schmeckt.
Aber nur weil es dir nicht schmeckt, ist es doch nicht böse, oder
verwerflich.
Solange du die Wahl hast, musst du das "Konzept der Benutzer-
definierten Casts" ja nicht verwenden.
EAF schrieb:> Es ist völlig ok, wenn dir das Verfahren nicht schmeckt.> Aber nur weil es dir nicht schmeckt, ist es doch nicht böse, oder> verwerflich.
Mit der Argumentation kann man auf jede Kritik antworten. Dir schmeckt
goto-Spaghetti nicht? Das macht es doch nicht böse oder verwerflich. Du
magst keine rohen Pointer? Das macht sie doch nicht böse oder
verwerflich.
Mit dem Unterschied, dass es im Gegensatz zu Spaghetticode ein modernes
Konzept ist. Nutzt du überhaupt modernes c++ (ab c++11)? Falls ja, bist
du mit der Einstellung in der Minderheit.
Mombert H. schrieb:> der Wahrheitswert eines basic_ios? Was ist der Wahrheitswert eines> shared_ptr? Was ist der Wahrheitswert eines shared_ptr<bool*>? Was ist> der Wahrheitswert eines std::optional?
Wenn das Verhalten der Klassen kennt, ist das offensichtlich.
avr schrieb:> Mit dem Unterschied, dass es im Gegensatz zu Spaghetticode ein modernes> Konzept ist. Nutzt du überhaupt modernes c++ (ab c++11)? Falls ja, bist> du mit der Einstellung in der Minderheit.
Ein modernes Konzept? Ich hab hier "More Effective C++" von 1996?
rumliegen. Da gibts schon ein Kapitel mit Titel "Be wary of user defined
conversion functions", das einige der Probleme auflistet.
> Mombert H. schrieb:>> der Wahrheitswert eines basic_ios? Was ist der Wahrheitswert eines>> shared_ptr? Was ist der Wahrheitswert eines shared_ptr<bool*>? Was ist>> der Wahrheitswert eines std::optional?>> Wenn das Verhalten der Klassen kennt, ist das offensichtlich.
Man muss also erst nachlesen wie es definiert ist, damit es
offensichtlich ist? Ist das das Argument? Ich habe nachgelesen, wie es
definiert ist und halte es trotzdem für unlogisch.
Mombert H. schrieb:> Dir schmeckt goto-Spaghetti nicht?
Mit goto habe ich keine Probleme, und löst auch keine Emotionen aus.
Spagetti, jeglicher Art, sind mir allerdings zuwider.
Damals, altes Basic, da gabs mal ein goto-Spaghetti Problem.
Lange ist her.....
War sicherlich ein Grund für mich, um davon fern zu bleiben.
Mombert H. schrieb:> Du magst keine rohen Pointer?
Ja, stimmt.
Drum verwende ich sie auch nur in höchster Not.
In modernem C++ gibts allerdings kaum Grund, das zu tun.
Es sei denn, man muss sich mit C Altlasten rum schlagen.
Aus meiner Sicht gibt es keine Sprachmittel, welche per se böse, oder
schlecht sind.
Es ist halt immer eine Frage des Einsatzzweckes.
Und hier if (peripheral) empfinde ich es als angemessen.
Da wird eben eine Funk- Instanz gefragt, ob sie verbunden, bzw.
funktionsfähig ist.
EAF schrieb:> Und hier if (peripheral) empfinde ich es als angemessen.> Da wird eben eine Funk- Instanz gefragt, ob sie verbunden, bzw.> funktionsfähig ist.
Nein, da wird gefragt, ob das peripheral true oder false ist. Das ist
etwas anderes. Und wie du feststellst ist auch schon unklar was die
genaue bedeutung ist. Oder gibt es keinen Unterschied zwischen verbunden
und funktionsfähig? Und wenn man sich die Implementation anschaut ist es
weder noch, da getestet wird, ob die Adresse 0 ist.
Mombert H. schrieb:> Da gibts schon ein Kapitel mit Titel "Be wary of user defined> conversion functions", das einige der Probleme auflistet.
Ja, und?
Sei vorsichtig!
Das Etikett kann man sicherlich an jedes Sprachmittel dran kleben.
Denn mit jedem Sprachmittel kann man Mist bauen.
Zudem wurde ja auch der explicit Modifizierer eingeführt.
Das mildert einige der alten Problemchen
Mombert H. schrieb:> Man muss also erst nachlesen wie es definiert ist,
Nicht die Definition/Code der Klasse ist maßgeblich, sondern das
Interface sollte man kennen, bevor man es verwendet.
EAF schrieb:> Mombert H. schrieb:>> Da gibts schon ein Kapitel mit Titel "Be wary of user defined>> conversion functions", das einige der Probleme auflistet.>> Ja, und?>> Sei vorsichtig!> Das Etikett kann man sicherlich an jedes Sprachmittel dran kleben.> Denn mit jedem Sprachmittel kann man Mist bauen.
Wir können auch die Formulierung "Avoid implicit conversion operators"
aus den C++-Core-Guidelines nehmen:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c164-avoid-implicit-conversion-operatorsEAF schrieb:> Zudem wurde ja auch der explicit Modifizierer eingeführt.> Das mildert einige der alten Problemchen
Ich bezweifle, dass die Person, die den obigen operator bool geschrieben
hat, da ein explicit dran schreiben wird. Es wäre aber schon lustig,
wenn da plötlich ein
1
if(static_cast<bool>(peripheral))
stehen würde, statt es zu peripheral.is_valid() oder
peripheral.has_address() zu ändern.
Mombert H. schrieb:> Und wie du feststellst ist auch schon unklar was die> genaue bedeutung ist.
Ist es nicht.
Es wird gefragt ob die Instanz verwendbar ist.
Diese Instanz antwortet mit ja oder nein.
So schwer ist das doch gar nicht.....
Mombert H. schrieb:> Und wenn man sich die Implementation anschaut ist es> weder noch, da getestet wird, ob die Adresse 0 ist.
Das ist ein Interna der Instanz.
Mit dem Arduino Serial ist es das gleiche!
if(Serial) fragt die Instanz, ob sie nutzbar ist.
Solange sie nicht mit true antwortet, macht es keinerlei Sinn da was hin
zu schicken.
ich finde es ist sehr offensichtlich was 'if (peripheral)' bewirken
soll. Was die Kriterien für eine Gültigkeit bzw. true sind, das sollte
man der Doku/Code/Debugger entnehmen. Bei Arduino ist es eben usus und
dann stellt man sich darauf ein. Wenn man es nicht toll findet, dann
benutzt man eben keine Libs und schreibt alles selber. Aber solchen
Inselcode finden andere nicht toll und du bleibst Einzelschicksal.
Johannes S. schrieb:> Wenn man es nicht toll findet
Manches mal kann man zwischen verschiedenen Schreibweisen aussuchen.
So sich die schönere raus suchen.
1
static_assert(is_integral<int>{},"Integral Type expected");
2
static_assert(is_integral<int>(),"Integral Type expected");
3
static_assert(is_integral<int>::value,"Integral Type expected");
Die mit ::value ist in meinen Augen nicht unbedingt die schönste.
Ich bevorzuge die erste, um (auch mir selber) klar zu machen, dass
is_integral keine Funktion ist.
Mombert H. schrieb:> Und bei welchem dieser Beispiele ist die Bedeutung dieser Konvertierung> nach bool offensichtlich?
Für mich bei so ziemlich allen. Und wenn bei einer API immer alles
offensichtlich wäre, bräuchte man keine Doku. Das wäre zwar ein schönes,
aber doch eher unerreichbares Ziel.
Übrigens ist auch für jedes dieser Beispiele ein Satz enthalten, der
erklärt, was der Operator macht.
> Was der Wahrheitswert eines basic_ios?
Es sagt aus, ob der Stream benutzbar ist. Da steht ja sogar dabei, warum
es das gibt:
"This operator makes it possible to use streams and functions that
return references to streams as loop conditions, resulting in the
idiomatic C++ input loops such as while(stream >> value) {...} or
while(getline(stream, string)){...}. Such loops execute the loop's body
only if the input operation succeeded."
> Was ist der Wahrheitswert eines shared_ptr?
Er sagt, ob er auf ein Objekt zeigt oder null ist, wie bei einem
klassischen Zeiger auch.
> Was ist der Wahrheitswert eines shared_ptr<bool*>?
Das gleiche.
> Was ist der Wahrheitswert eines std::optional<bool>?
Es sagt, ob in dem std::optional ein Wert steht oder nicht. Das ist
quasi die selbe Semantik wie bei einem Pointer.
> Ich kann bei keinem, der von dir gelisteten Typen, die Frage "Was ist> der Wahrheitswehrt von X?" beantworten.
Außer für basic_ios, wo ich es schon vorher wusste, hab ich oben bei
allen einfach mal intuitiv geschrieben, was ich erwarte. Dann habe ich
nachgelesen, und es war auch genau das. Ich finde alle diese Operatoren
intuitiv.
> Echt? Wie kann es in Ordnung sein, dass der Wahrheitswert eines> Bluetooth-Devices mit seiner Adresse zu tun hat?
Ist wie bei einem Pointer. Auch dessen Wahrheitswert hängt von der
enthaltenen Adresse ab, und zwar auf exakt die selbe Weise: Wenn sie
null ist (und nur dann), ist der Wert false.
> Und wie kann es in Ordnung sein, dass in C++ die Adresse mit memcpy> verglichen wird?
Das wird sie zum Glück nicht, sondern mit memcmp, was auch sehr viel
geeigneter dafür erscheint.