gpt4 book ai didi

c++ - 使用循环从外部文件填充结构

转载 作者:太空狗 更新时间:2023-10-29 22:54:07 24 4
gpt4 key购买 nike

我有一个包含这个表的 lua 脚本:

test = {}
test[1] = "Naya"
test[2] = 1000
test[3] = 1
test[4] = 20

我的 C++ 程序中有一个结构体。旨在填充该表中包含的信息:

//Enemy Struct
struct Enemy
{
string name;
int health;
int family;
int level;
} enemy;

为已知大小和已知键名的表填充结构非常容易。

当出现以下情况时,它会变得更具挑战性:

  • 一个未知大小的表格(很容易找到表格长度)
  • 数字键名。 (简单到只用我)
  • 填写结构(我遇到问题的部分)

我想要的是使用一个简单的 for 循环来填充这个结构,如下所示:

for (int i = 1; i < length; i++)
{
lua_pushnumber(L, i);
lua_gettable(L, -2);
if (lua_isnumber(L, -1))
enemy.at(i)? = lua_tonumber(L, -1);
else
enemy.at(i) ? = lua_tostring(L, -1);

lua_pop(L, 1);
}

Struct 没有.at(x) 函数。因此我不能使用这个简单的循环遍历结构来填充它。

我考虑过使用带有 vector/结构的二维数组。但我不确定这是否有效。

我希望 Struct 使用循环填充来自 lua 脚本的数据。

最佳答案

您需要某种反射才能动态获取索引 i 处的成员。
不幸的是,标准 C++ 中没有任何东西可以为您做到这一点。

有几种方法可以让它发挥作用:

  • 最简单的解决方案是只读取值并将它们直接分配给敌人对象,例如:
Enemy e;
lua_pushnumber(L, 1);
lua_gettable(L, -2);
e.name = lua_tostring(L, -1);
// ...

但是,如果您有很多成员,这将很快变得非常困惑。

  • 假设您可以对所有成员(例如所有字符串)使用相同的类型,您可以使用 vector 而不是 Enemy 结构,例如:
std::vector<std::string> enemy;
for(int i = 0; i < length; i++) {
lua_pushnumber(L, i);
lua_gettable(L, -2);
enemy.push_back(lua_tostring(state, -1));
lua_pop(L, 1);
}

此解决方案的明显缺点是您需要在 vector 中使用索引,而不是像 healthname 等花哨的名称。到单一类型。

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/algorithm/iteration.hpp>
#include <lua/lua.hpp>

struct Enemy
{
std::string name;
int health;
int family;
int level;
} enemy;

BOOST_FUSION_ADAPT_STRUCT(
Enemy,
(std::string, name)
(int, health)
(int, family)
(int, level)
)

struct LuaVisitor {
LuaVisitor(lua_State* state) : idx(1), state(state) {}

void operator()(std::string& strVal) const {
next();
// TODO: check if top of stack is actually a string (might be nil if key doesn't exist in table)
strVal = lua_tostring(state, -1);
lua_pop(state, 1);
}

void operator()(int& intVal) const {
next();
// TODO: check if top of stack is actually a number (might be nil if key doesn't exist in table)
intVal = lua_tonumber(state, -1);
lua_pop(state, 1);
}

void next() const {
lua_pushnumber(state, idx++);
lua_gettable(state, -2);
}

mutable int idx;
lua_State* state;
};


int main(int argc, char* argv[]) {
// create a sample table
lua_State* state = luaL_newstate();
luaL_dostring(state, "return {\"Hello World\", 1337, 12, 123}");

// read the enemy from the table
Enemy e;
boost::fusion::for_each(e, LuaVisitor(state));

std::cout << "[Enemy] Name: " << e.name << ", health: " << e.health << ", family: " << e.family << ", level: " << e.level << std::endl;

lua_close(state);
return 0;
}

这将使您能够动态设置 Enemy 结构的成员,但是 boost 非常重量级,您需要保留 BOOST_FUSION_ADAPT_STRUCT 宏与实际结构保持同步。

  • 您还可以使用 lua 绑定(bind)库,例如luaaa将 Enemy 对象直接映射到 lua(而不是传递一个表):
#include <lua/luaaa.h>

struct Enemy
{
Enemy() {}
virtual ~Enemy() {}

void init(std::string _name, int _health, int _family, int _level) {
name = _name;
health = _health;
family = _family;
level = _level;
}

std::string name;
int health;
int family;
int level;
};

void myFunction(Enemy* e) {
std::cout << "[Enemy] Name: " << e->name << ", health: " << e->health << ", family: " << e->family << ", level: " << e->level << std::endl;
}

int main(int argc, char* argv[]) {
// init lua & bindings
lua_State* state = luaL_newstate();
luaaa::LuaClass<Enemy> luaEnemy(state, "Enemy");
luaEnemy
.ctor()
.fun("init", &Enemy::init);
luaaa::LuaModule mod(state, "sampleModule");
mod.fun("myFunction", myFunction);

luaL_dostring(state, R"(
enemy = Enemy.new()
enemy:init("My Enemy", 1, 2, 3)
sampleModule.myFunction(enemy)
)");

lua_close(state);
return 0;
}

然后就可以直接在lua中使用敌人对象了:

enemy = Enemy.new()
enemy:init("My Enemy", 1, 2, 3)
sampleModule.myFunction(enemy)

希望其中一个选项涵盖您的用例;)

关于c++ - 使用循环从外部文件填充结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57382553/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com