Chromium Chronicle Nr. 24: StrongAlias, IdType und TokenType

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 von int32_t als Kennung.
  • Verwende base::TokenType<TagType> anstelle eines unspezifischen base::UnguessableToken.
  • Verwenden Sie eine enum-Klasse anstelle eines booleschen Werts. (z. B. kForReload, kNotForReload statt true, false).
  • Ersetzen Sie andere unspezifische Typen durch base::StrongAlias<TagType, SomeWrappedType>.