Odcinek 24: Łukasz Anforowicz w Bellevue, Waszyngton (sierpień 2021 r.)
Poprzednie odcinki
Czy dostrzegasz błąd w kodzie poniżej? Czy widzisz błąd podczas weryfikacji kodu tylko w witrynie wywoławczej?
Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
Ten sam typ może czasem reprezentować wartości z niezgodnych domen.
Zwykle dzieje się tak w przypadku niekonkretnych typów danych, takich jak liczby całkowite lub ciągi znaków.
Powyższy przykład pokazuje, jak może to powodować błędy.
Na szczęście w //base
Chromium ułatwia wprowadzanie niepowtarzalnych typów treści dla dorosłych:
#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);
Oddzielne typy zwiększają czytelność.
Dodatkowo StrongAlias
wyłapuje miksy typów podczas kompilacji:
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);
^
Kompilator zauważa, że te typy są niezgodne, bo mają inny typ „tagu”.
Typ StrongAlias
akceptuje dowolny typ tagu.
Przykład pokazuje, że typ „tag” nie wymaga nigdzie definicji typu – wystarczy w tym przypadku umieścić w swojej witrynie deklarację nieistniejącej klasy.
W przyszłości zamiast korzystać z nieokreślonego typu (np. wartości logicznej, typu int czy ciągu znaków) możesz:
- Używaj
base::IdType32<TagType>
zamiastint32_t
jako identyfikatora. - Użyj
base::TokenType<TagType>
zamiast konkretnejbase::UnguessableToken
. - Użyj klasy enum zamiast wartości logicznej (np.
kForReload
,kNotForReload
zamiasttrue
,false
). - Inne nieokreślone typy zastąp wartością
base::StrongAlias<TagType, SomeWrappedType>
.