【问题标题】:Generic types with c++ and lua使用 c++ 和 lua 的泛型类型
【发布时间】:2014-11-29 21:52:28
【问题描述】:

我有一个Entity 类,其中包含一些属性(数据片段)。这些属性存储在 name => value 的映射中。

class Entity
{
public:
    // Sets the attribute with the specified name.
    void attribute(const std::string& name, const GenericType& value) {
        m_attributes[name] = value;
    }

    // Returns the attribute with the specified name.
    GenericType& attribute(const std::string& name) {
        return m_attributes[name];
    }

    template<typename AttributeType>
    void attribute(const std::string& name, const AttributeType& value) {
        m_attributes[name] = GenericType(value);
    }

    template<typename AttributeType>
    AttributeType& attribute(const std::string& name) {
        return generic_cast<AttributeType>(m_attributes[name]);
    }

private:
    // Map of attributes from name => value.
    std::unordered_map<std::string, GenericType> m_attributes;
}

我有一个创建或覆盖属性的方法和另一个返回具有指定名称的属性的方法。前两种方法暴露给 Lua。最后两种方法用于访问和修改我的 c++ 源代码中的属性。问题是属性可以是任何类型。例如,我希望能够做到:

entity.attribute("Health", 100)
entity.attribute("Position", Vector3(1,2,3))
entity.attribute("Position").x = 4

应该可以从我的 c++ 源文件和 lua 脚本中读取和修改属性。我以前一直在使用 ChaiScript,我使用 Boxed_Value 类作为我的 GenericType。这工作得很好,但过多的编译时间迫使我寻找其他地方。

有没有办法通过 LuaBind(或任何其他 Lua 绑定库)实现这一点? luabind::object 类看起来很有希望,但它的构造函数中需要一个 lua_State 指针。这让我很担心,因为我觉得 Entity 类真的不应该知道关于 Lua 状态的任何事情。

【问题讨论】:

  • 如果您请求支持 ChaiScript 编译时间会很有帮助,有一些技术可以减少它。
  • @lefticus 我能够减少编译时间,我仍然在使用 ChaiScript,因为我真的很喜欢这种语言。由于我使用 ChaiScript 获得的编译时间,这个问题并没有真正提出。我还对其他语言绑定库如何处理泛型类型感兴趣。
  • 很好,感谢更新。

标签: c++ lua luabind


【解决方案1】:

在 LuaBind 中,您的实体类不需要了解任何有关 lua 状态的信息。 Lua 绑定不必在语法上与 C++ API 一对一相同,因为它们是完全不同的语言。

在您的情况下,我宁愿将 api 拆分为 getter 和 setter。使用显示的Entity 类,您可能会难以让 LuaBind 明确地执行您想做的事情。您可以做的是在 C++ 端为 Entity 编写一个包装类,该类将具有符合 LuaBind 的简单接口,即使用明确的名称拆分 getter 和 setter。

Blufs 是一个例子,说明我的意思。

举个简单的例子,with LuaBridge:

创建一个简单的非手卷装订有点棘手:

class Entity {
    std::map<std::string, int> attributes;

public:
    void attribute(std::string const& key,int value) {
        attributes[key] = value;
    }

    int& attribute(std::string const& key) {
        return attributes[key];
    }
};

可以改为绑定包装器:

class EntityWrapper {
    Entity entity;
public:
    void set_int(std::string const& key,int value) {
        entity.attribute(key,value);
    }


    int get_int(std::string const& key) {
        return entity.attribute(key);
    }
};

一个简单的绑定:

void luabridge_bind(lua_State *L) {
 luabridge::getGlobalNamespace(L)
 .beginClass<EntityWrapper>("Entity")
 .addConstructor<void(*)(), RefCountedPtr<EntityWrapper> /* creation policy */ >()
    .addFunction("get_int", &EntityWrapper::get_int)
    .addFunction("set_int", &EntityWrapper::set_int)
 .endClass()
 ; 
}

在 Lua 中:

local e = Entity()
e:set_int("bla",42)
print(e:get_int("bla"))

如果您需要 Entity 与其他 API 进行交互,请编写小的包装器来获取原始包装对象并将其传递给其他函数。

【讨论】:

  • 感谢您的详细回复。我的问题是我不知道先验的特定属性类型。所以我不能编写特定类型的 getter 和 setter 方法。
  • 在这种情况下,如果我没记错的话,拥有脚本 API 将非常困难。您有时必须枚举脚本绑定中使用的所有类型。如果它是一个选项,您可以创建一个元程序,如果脚本 API 中缺少值转换器或绑定,则该元程序将无法编译。但是,您必须修改通用方法才能成为元程序的一部分。即static_assert(has_binding&lt;AttributeType&gt;::value,...) 或任何就足够了
  • @Homar 既然你在使用模板,你不需要知道编译时存在哪些类型和属性吗?
  • 是的,在编译时。但我不想对特定类型的 getter 和 setter 方法进行硬编码。如果我能让编译器生成这些,那么我认为这将是一个很好的解决方案。我必须使用 LuaBind 注册类,所以除了原始类型之外,我还需要所有这些类型的 getter 和 setter 方法。
  • 必须有人知道如何将MySuperType 转换为一组数字、字符串和布尔值,所以,没有办法绕过它。典型的 C++ 编译器没有那种 AI。但是您可以使用元程序帮助自己以声明的方式生成值转换器。如果您可以进行托管,请将您的代码转换为托管代码,您将获得更多“免费”
猜你喜欢
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多