Folge 24: von Łukasz Anforowicz in Bellevue, Washington (August 2021)
Vorherige Folgen
Erkennst du den Fehler im Code unten? Würdest du die Programmfehler bei einer Codeüberprüfung wenn ich nur die Anrufseite anschaue?
Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
Derselbe Typ kann manchmal Werte aus inkompatiblen Domains darstellen.
Dies geschieht normalerweise bei unspezifischen Datentypen wie Ganzzahlen oder Zeichenfolgen.
Das Beispiel oben zeigt, wie dies zu Fehlern führen kann.
Mit //base
von Chromium kannst du ganz einfach explizite, unterschiedliche Typen verwenden:
#include "base/types/strong_alias.h"
// The first template argument of StrongAlias is a "tag" type.
// The "tag" type is used to distinguish between different
// StrongAlias types.
using CommandData = base::StrongAlias<class CommandDataTag, int>;
using CommandBufferId = base::StrongAlias<class CommandBufferIdTag, int>;
Token CreateToken(CommandData command_data, CommandBufferId buffer_id);
Separate Typen verbessern die Lesbarkeit.
Außerdem erkennt StrongAlias
Typverwechslungen bei der Kompilierung:
test.cc:456:16: error: no matching function for call to 'CreateToken'
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
^~~~~~~~~~~
test.cc:123:7: note: candidate function not viable: no known conversion from
'StrongAlias<class CommandBufferIdTag, [...]>' to
'StrongAlias<class CommandDataTag, [...]>' for 1st argument
Token CreateToken(CommandData command_data, CommandBufferId buffer_id);
^
Der Compiler sieht,
dass die Typen nicht kompatibel sind,
weil sie ein anderes „Tag“ Typ.
StrongAlias
akzeptiert jeden beliebigen Typ als Tag. Typ.
Das Beispiel zeigt, dass das „Tag“ braucht für einen Typ nirgendwo eine Typdefinition –
die Deklaration einer nicht vorhandenen Klasse funktioniert.
Künftig werden anstelle eines unspezifischen Typs (z. B. bool, int, string) sollten Sie diese Alternativen in Betracht ziehen:
- Verwenden Sie
base::IdType32<TagType>
anstelle vonint32_t
als Kennung. - Verwende
base::TokenType<TagType>
anstelle eines unspezifischenbase::UnguessableToken
. - Verwenden Sie eine enum-Klasse anstelle eines booleschen Werts.
(z. B.
kForReload
,kNotForReload
statttrue
,false
). - Ersetzen Sie andere unspezifische Typen durch
base::StrongAlias<TagType, SomeWrappedType>
.