在运行时根据函数名匹配调用函数

时间:2014-01-02 16:25:39

标签: c++ c++11

事先道歉可能含糊不清的标题,我能想出最好的。

我有以下C ++和文本文件:

cpp文件:

class Test
{
        int var1;
        int var2;

    public:
        bool set_var1();
        bool set_var1();

        bool set(string var_name);

        void process_file();
}

文本文件:

var1 value1
var2 value2

目标 - 在process_file()中,读取/解析文本文件,并为文件中的每个varX调用相应的set_varX()。

一个选项,在函数set()中,将var_name与“var1”/“var2”/ etc进行比较,以及 调用相应的set_varX()。我对这种方法的问题更多 行被添加到文本文件中,代码变得......丑陋,带有长“if-else” set()中的代码块。

另一个选项,创建一个静态地图    “var1”set_var1()    “var2”set_var2()

set()将遍历地图,并在字符串比较匹配时调用相应的func_ptr。此选项需要维护地图结构。

虽然我更喜欢第二个选项,但是随着测试文件的增加,代码更改的更少,是否还有其他选择。只是大声思考,在set()中,我可以取字符串var_name,并在pre_之前调用set_var_name(),基本上以某种方式避免字符串比较,这在上述两种情况下都可以完成。我的直觉是,在C ++中,在运行时不可能做到

谢谢你, 艾哈迈德。

3 个答案:

答案 0 :(得分:2)

听起来你问的是反射,这不是C ++的一个特性,所以这是不可能的。正如您所指出的,该问题有解决方案,但所有这些都涉及到字符串名称到函数的映射,您必须自己构建/维护该映射。语言不适合你。

答案 1 :(得分:0)

您可以通过创建var1,var2 ..自注册类型来改进选项2。新关键字不会导致代码更改,只会导致新类型。因此,地图必须是某种全球对象,单身等等。

一个非常简单的例子:

struct Setter
{
    virtual ~Setter() = default;
    virtual void Process(std::string content) const = 0;
};

class SetterMap
{
public:
    bool RegisterSetter(std::string keyword, std::unique_ptr<Setter> setter) {
        setters[keyword] = move(setter);
        return true;
    }

    const Setter& GetSetter(const std::string& keyword) const {
        return *(setters.at(keyword));
    }
private:
    std::map<std::string, std::unique_ptr<Setter>> setters;
};


inline SetterMap& GetSetterMap() {
    static SetterMap map;
    return map;
}

定义并注册一些setter:

struct Var1 : Setter {
    void Process(std::string content) const override {

    }
};
namespace {
    bool var1registered = GetSetterMap().RegisterSetter(
        "var1", std::make_unique<Var1>());
}

struct Var2 : Setter {
    void Process(std::string content) const override {

    }
};
namespace {
    bool var2registered = GetSetterMap().RegisterSetter(
        "var2", std::make_unique<Var2>());
}

使用setter map:

int main()
{
    std::string line = "var1: blablab";
    GetSetterMap().GetSetter("var1").Process(line);
}

答案 2 :(得分:0)

根据您的需要,您可以考虑嵌入Lua并将文本文件的语法更改为:

test.var1 = 1234
test.var2 = 42

这里,test将是一个全局Lua表,您可以从C ++端实例化并使用lua_setmetatable()分配metatable。 metatable将有一个__newindex方法,如here所述。如果您熟悉Python,这有点像提供__setattr__元方法,即它拦截不存在的字段的分配并执行一些用户指定的魔法。

你的案例中的'技巧'是在Lua中创建一个metatable,它将var1的{​​{1}},var2等字段的访问重新路由到{{3}包装器,用于设置基础test对象上的相应字段。之后,您只需使用lua_CFunction“运行”该文件即可。

一个快速肮脏的例子(针对Lua 5.1.5测试)说明了这个想法的要点如下。 (由于使用了原始字符串文字,因此需要使用Test进行编译。)

如果您的需求非常特定/有针对性,这种方法肯定是矫枉过正的。但是,如果您希望/需要在您的应用程序中编写脚本,无论如何,嵌入Lua是一个很好的解决方案。

注意:严格必需使用单独的表格(例如,示例中为-std=c++11)。 Lua将全局变量存储在名为test的表中,因此您可以为_G设置元表。但是,这样做有点像黑客;它使示例更难以遵循,并将限制在宿主应用程序中使用Lua的其他一些方法。

_G