The Chromium Chronicle #24: StrongAlias, IdType, and TokenType

Posted on Jan 12, 2023
标题The Chromium Chronicle #24: StrongAlias, IdType, and TokenType
作者Łukasz Anforowicz in Bellevue, WA
发表时间August, 2021
地址https://developer.chrome.com/blog/chromium-chronicle-24/

你能发现下面代码中的错误吗?当你在Chroumium上进行代码审查的时候,你还能发现这个错误吗?比如这里这里

Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());

有时候相同的数据类型可能代表着完全不兼容的数据,特别是像integers或者strings等一些基础数据类型。上面的例子生动的说明了这种错误是怎么发生的。还好的是,Chromium的//base引入了一种方法可以创建明确清晰的不同类型:

#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 types improve readability. Additionally, StrongAlias catches type mix-ups at compile time:

独立的类型明显地提高了可读性。另外StrongAlias也可以在编译器捕获不同的类型混用的错误:

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);
      ^

由于他们有不同的tag类型,所以编译器会将这两种类型当做是不同的不兼容的类型。StrongAlias可以将任意的类型当作为tag类型,甚至是使用不存在实际定义的原位前向声明类都可以。上面的例子中的class CommandDataTagclass CommandBufferIdTag实际上并没有定义。

在以后的编程中,考虑使用下面的替代类型而不是原始的基础数据类型(比如bool,int,string等):

  • 使用base::IdType32<TagType>而不是int32_t
  • 使用base::TokenType<TagType>而不是base::UnguessableToken
  • 使用enum class而不是bool(比如,kForReloadkNotForReload而不是truefalse)
  • 使用base::StrongAlias<TagType, SomeWrappedType>替换其他的基础数据类型