You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中如何高效存储并检索类/结构内的多类型Token值?

优化C++解释器Token值存储与检索的方案

问题背景

我正在用C++开发一个基础语言解释器,用于学习和实践。需要存储词法分析得到的Token,且Token需能存储对应的值(如int、string、float字面量),同时要能以最少代码高效检索这些值。

最初我仅存储Token的文本,在需要时由解释器转换为int或float,但发现这种方式效率极低(如循环中大量字符串转换场景)。之后我采用了基类+子类的方案:

class Token {
public:
    Type m_type;
    std::string m_text;

    Token(const std::string& text, const Type& type) : m_text(text), m_type(type) {} 

    virtual void getValue(int&) = 0;
    virtual void getValue(double&) = 0;
    virtual void getValue(std::string&) = 0;
    virtual ~Token() {}
};

class IntToken : public Token {
public:
    int m_data;

    IntToken(const std::string& text, const Type& type, const int& data) : 
        Token(text, type), m_data(data) {}

    void getValue(int& val) {
       val = m_data;
    } 
    void getValue(double& val) {}
    void getValue(std::string&) {}
};

其余子类与IntToken类似,仅存储的数据类型不同,通过std::vector<Token*> tokens;来存储所有Token。但问题在于每次检索值时都需要判断Token类型,代码中会出现大量switch语句,检索操作非常繁琐。

解决方案

方案一:使用std::variant(C++17及以上)

std::variant是C++17引入的类型安全联合体,可直接存储多种类型的值,无需维护继承体系,代码简洁且类型安全。

实现示例:

#include <variant>
#include <string>

enum class TokenType {
    Int, Float, String, Identifier // 可扩展其他Token类型
};

struct Token {
    TokenType type;
    std::string text;
    std::variant<int, double, std::string> value;
};

// 存储Token的容器
std::vector<Token> tokens;

检索值时用std::visit处理不同类型,避免switch:

// 示例:遍历处理Token值
void process_int(int val) { /* 处理int逻辑 */ }
void process_double(double val) { /* 处理double逻辑 */ }
void process_string(const std::string& val) { /* 处理string逻辑 */ }

for (const auto& token : tokens) {
    std::visit([&](auto&& val) {
        using T = std::decay_t<decltype(val)>;
        if constexpr (std::is_same_v<T, int>) {
            process_int(val);
        } else if constexpr (std::is_same_v<T, double>) {
            process_double(val);
        } else if constexpr (std::is_same_v<T, std::string>) {
            process_string(val);
        }
    }, token.value);
}

优势:

  • 无需继承体系,代码量大幅减少
  • 编译期类型检查,避免运行时转换错误
  • 内存效率高,仅占用最大类型的内存+少量额外开销

方案二:访问者模式(兼容C++17以下版本)

若需保留继承体系,可通过访问者模式消除switch语句,将类型判断逻辑封装到访问者类中。

首先修改Token基类,添加accept方法:

class TokenVisitor;

class Token {
public:
    Type m_type;
    std::string m_text;

    Token(const std::string& text, const Type& type) : m_text(text), m_type(type) {} 
    virtual void accept(TokenVisitor& visitor) = 0;
    virtual ~Token() {}
};

// 定义访问者基类
class TokenVisitor {
public:
    virtual void visit(IntToken& token) = 0;
    virtual void visit(FloatToken& token) = 0;
    virtual void visit(StringToken& token) = 0;
    // 新增Token类型时添加对应visit方法
};

子类实现accept方法:

class IntToken : public Token {
public:
    int m_data;

    IntToken(const std::string& text, const Type& type, const int& data) : 
        Token(text, type), m_data(data) {}

    void accept(TokenVisitor& visitor) override {
        visitor.visit(*this);
    }
};

// FloatToken、StringToken同理实现accept方法

使用时创建具体访问者处理逻辑:

class ValueProcessor : public TokenVisitor {
public:
    void visit(IntToken& token) override {
        process_int(token.m_data);
    }

    void visit(FloatToken& token) override {
        process_float(token.m_data);
    }

    void visit(StringToken& token) override {
        process_string(token.m_data);
    }
};

// 使用示例
ValueProcessor processor;
for (auto* token : tokens) {
    token->accept(processor);
}

优势:

  • 消除冗余switch语句,符合开闭原则,新增Token类型只需扩展访问者方法
  • 逻辑集中在访问者类中,代码结构更清晰

方案三:std::any(C++17及以上)

std::any可存储任意类型,但需运行时类型检查,类型安全性弱于std::variant,适合类型不确定的场景,解释器Token场景下优先级低于前两种方案。

示例:

#include <any>
#include <string>

struct Token {
    TokenType type;
    std::string text;
    std::any value;
};

// 检索值示例
if (token.type == TokenType::Int) {
    int val = std::any_cast<int>(token.value);
    process_int(val);
}

总结

若使用C++17及以上版本,std::variant是最优选择,兼顾简洁性、类型安全与效率;若需保留继承体系,访问者模式可有效消除switch语句,提升代码可维护性。

内容的提问来源于stack exchange,提问作者Tiberiu Popescu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:23:14