移植Crafting Interpreters Java代码到C++如何处理Object类型literal字段
解决方案
你可以直接使用C++标准库提供的类型擦除容器实现需求,不需要自己编写继承体系,对应两种场景可选:
方案1:优先使用std::variant(推荐,适配解释器场景)
解释器中字面量的类型是固定有限的,只会是空值、数字、字符串、布尔值几种,std::variant性能更高、类型安全,没有额外的运行时开销:
- 首先定义字面量可承载的类型集合,用
std::monostate对应Java的null空值:
#include <variant> // 空值占位类型对应Java null,按需扩展后面的类型列表即可 using Literal = std::variant<std::monostate, double, std::string, bool>;
- 改写Token类:
class Token { private: TokenType type; std::string lexeme; std::size_t col; std::size_t line; Literal literal; public: // 对应无literal的构造场景 Token(TokenType type, std::string lexeme, std::size_t col, std::size_t line) : type(type), lexeme(std::move(lexeme)), col(col), line(line), literal(std::monostate{}) {} // 对应带literal的构造场景 Token(TokenType type, std::string lexeme, Literal literal, std::size_t col, std::size_t line) : type(type), lexeme(std::move(lexeme)), literal(std::move(literal)), col(col), line(line) {} std::string to_string() const { std::string literal_str; std::visit([&](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, std::monostate>) { literal_str = "null"; } else if constexpr (std::is_same_v<T, double>) { literal_str = std::to_string(arg); } else if constexpr (std::is_same_v<T, std::string>) { literal_str = arg; } else if constexpr (std::is_same_v<T, bool>) { literal_str = arg ? "true" : "false"; } }, literal); // 补充TokenType转字符串逻辑后拼接返回即可 return tokenType_to_string(type) + " " + lexeme + " " + literal_str; } };
- 对应实现addToken重载即可:
void addToken(TokenType type) { addToken(type, std::monostate{}); } void addToken(TokenType type, Literal literal) { std::string text = source.substr(start, current - start); tokens.emplace_back(type, std::move(text), std::move(literal), col, line); }
方案2:使用std::any适配完全任意类型
如果后续确实需要承载未提前定义的任意类型,可以用std::any,只需要在取值时做类型校验:
#include <any> class Token { private: TokenType type; std::string lexeme; std::size_t col; std::size_t line; std::any literal; public: Token(TokenType type, std::string lexeme, std::size_t col, std::size_t line) : type(type), lexeme(std::move(lexeme)), col(col), line(line) {} template<typename T> Token(TokenType type, std::string lexeme, T&& literal_val, std::size_t col, std::size_t line) : type(type), lexeme(std::move(lexeme)), literal(std::forward<T>(literal_val)), col(col), line(line) {} // 取值时使用std::any_cast即可,可捕获bad_any_cast异常处理类型不匹配场景 };
两种方案都需要C++17及以上标准支持,目前主流编译器都默认支持该标准。
内容的提问来源于stack exchange,提问作者foragerDev
相关产品推荐
相关产品推荐

