Chromium Chronicle #24: StrongAlias, IdType และ TokenType

ตอนที่ 24: โดย Łukasz Anforowicz ใน Bellevue, วอชิงตัน (สิงหาคม 2021)
ตอนก่อนหน้า

คุณหาข้อบกพร่องในโค้ดด้านล่างได้ไหม เธอจะเห็นไหม ข้อบกพร่อง ในการตรวจสอบโค้ด เมื่อดูแค่ในเว็บไซต์ Callsite

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

บางครั้งประเภทเดียวกันอาจแสดงค่าจากโดเมนที่ใช้ร่วมกันไม่ได้ ซึ่งมักเกิดขึ้นสำหรับข้อมูลประเภทที่ไม่เฉพาะเจาะจง เช่น จำนวนเต็มหรือสตริง ตัวอย่างด้านบนแสดงให้เห็นว่าการดำเนินการนี้อาจทำให้ข้อบกพร่องเกิดขึ้นได้อย่างไร โชคดีที่ //base ของ Chromium ทำให้คุณแนะนำประเภทที่แตกต่างกันอย่างชัดเจนได้อย่างง่ายดาย ดังนี้

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

การแยกประเภทจะช่วยให้อ่านง่ายขึ้น นอกจากนี้ 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);
      ^

เมื่อคอมไพเลอร์จะเห็น ประเภทที่ใช้ร่วมกันไม่ได้ เพราะมี "แท็ก" ที่ต่างกัน ประเภท StrongAlias ยอมรับประเภทใดก็ได้เป็น "แท็ก" ประเภท ตัวอย่างนี้แสดงให้เห็นว่า "แท็ก" ไม่จำเป็นต้องกำหนดประเภทด้วยซ้ำในทุกที่ การประกาศล่วงหน้าว่าไม่มีคลาสที่มีอยู่จริงนั้นใช้ได้ดี

ในอนาคต แทนที่จะเป็นประเภทที่ไม่เจาะจง (เช่น bool, int, สตริง) โปรดพิจารณาทางเลือกต่อไปนี้

  • ใช้ base::IdType32<TagType> แทนการใช้ int32_t เป็นตัวระบุ
  • ใช้ base::TokenType<TagType> แทน base::UnguessableToken ที่ไม่เฉพาะเจาะจง
  • ใช้คลาส enum แทนบูลีน (เช่น kForReload, kNotForReload แทนที่จะเป็น true, false)
  • แทนที่ประเภทอื่นๆ ที่ไม่เฉพาะเจาะจงด้วย base::StrongAlias<TagType, SomeWrappedType>