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

Emscripten绑定C++类时部分重载方法在JS中无法调用

问题:Emscripten绑定C++重载方法时,Parser参数的重载无法正确调用

场景重现

我通过Emscripten将C++的RuleContext类绑定到JavaScript/TypeScript,该类包含三个toStringTree重载方法:

class RuleContext : public tree::ParseTree {
  public:
    virtual std::string toStringTree(Parser *recog, bool pretty = false) override;
    virtual std::string toStringTree(std::vector<std::string> &ruleNames, bool pretty = false);
    virtual std::string toStringTree(bool pretty = false) override;
};

对应的Emscripten绑定代码:

class_<RuleContext, base<tree::ParseTree>>("RuleContext")
    .function("toStringTree", select_overload<std::string(Parser *, bool)> (&RuleContext::toStringTree), allow_raw_pointers())
    .function("toStringTree", select_overload<std::string(std::vector<std::string> &, bool)> (&RuleContext::toStringTree))
    .function("toStringTree", select_overload<std::string(bool)> (&RuleContext::toStringTree))
    .allow_subclass<RuleContextWrapper>("RuleContextWrapper");

TypeScript声明:

export declare class RuleContext extends Extendable {
    public toStringTree(recognizer: Parser, pretty: boolean): string;
    public toStringTree(ruleNames: Vector<string>, pretty: boolean): string;
    public toStringTree(pretty: boolean): string;
}

目前仅两个重载可正常调用:

console.log(tree.toStringTree(names, true));
console.log(tree.toStringTree(true));

但调用传入Parser实例的重载时:

console.log(tree.toStringTree(parser, true));

出现以下错误:

BindingError: Expected null or instance of StringVector, got an instance of Recognizer
    at throwBindingError (file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:3910:8)
    at upcastPointer (file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:4652:4)
    at RegisteredPointer.nonConstNoSmartPtrRawPointerToWireType [as toWireType] (file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:4760:12)
    at Test1Context.RuleContext$toStringTree (eval at newFunc (file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:4957:22), <anonymous>:9:26)
    at proto.<computed> [as toStringTree] (file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:4612:61)
    at file:///Volumes/Extern/Work/projects/antlr4wasm/tests/test.ts:24:22

补充:StringVector是std::vector<std::string>的绑定类型,Recognizer是Parser的基类。

问题原因

Emscripten的函数重载匹配逻辑依赖参数数量和类型识别,但对于两个参数数量相同的重载(Parser* + bool 和 std::vector<std::string>& + bool),JavaScript层面无法精确区分自定义C++类型的实例,导致绑定系统误将Parser实例匹配到期望StringVector的重载,从而抛出类型转换错误。

解决方案

方案1:为重载方法指定不同的JS函数名

直接避免重载冲突,给两个双参数的重载分配不同的名称,修改Emscripten绑定代码:

class_<RuleContext, base<tree::ParseTree>>("RuleContext")
    // 给Parser参数的重载单独命名
    .function("toStringTreeWithParser", select_overload<std::string(Parser *, bool)> (&RuleContext::toStringTree), allow_raw_pointers())
    // 给Vector参数的重载单独命名
    .function("toStringTreeWithRuleNames", select_overload<std::string(std::vector<std::string> &, bool)> (&RuleContext::toStringTree))
    // 保留单参数重载的原名
    .function("toStringTree", select_overload<std::string(bool)> (&RuleContext::toStringTree))
    .allow_subclass<RuleContextWrapper>("RuleContextWrapper");

同步更新TypeScript声明:

export declare class RuleContext extends Extendable {
    public toStringTreeWithParser(recognizer: Parser, pretty: boolean): string;
    public toStringTreeWithRuleNames(ruleNames: Vector<string>, pretty: boolean): string;
    public toStringTree(pretty: boolean): string;
}

调用时使用对应名称即可:

console.log(tree.toStringTreeWithParser(parser, true));

方案2:调整重载绑定顺序并确保类型注册正确

如果希望保留原函数名,可尝试调整重载的绑定顺序,同时确保Parser类已正确完成Emscripten绑定并注册继承关系:

// 先绑定基类Recognizer
class_<Recognizer>("Recognizer");
// 再绑定Parser,指定基类
class_<Parser, base<Recognizer>>("Parser");

// 调整RuleContext的重载绑定顺序,将Parser参数的重载放在最后
class_<RuleContext, base<tree::ParseTree>>("RuleContext")
    .function("toStringTree", select_overload<std::string(bool)> (&RuleContext::toStringTree))
    .function("toStringTree", select_overload<std::string(std::vector<std::string> &, bool)> (&RuleContext::toStringTree))
    .function("toStringTree", select_overload<std::string(Parser *, bool)> (&RuleContext::toStringTree), allow_raw_pointers())
    .allow_subclass<RuleContextWrapper>("RuleContextWrapper");

此方案依赖Emscripten的匹配顺序,稳定性不如方案1,若仍有问题建议优先使用方案1。

内容的提问来源于stack exchange,提问作者Mike Lischke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:54:57