我想将C++创建的对象作为LUA函数参数进行调用, 该如何处理?
-- this is example.lua
function onMessage(obj)
print('===========', obj:getName())
end
// this is cat.h
#pragma once
#include <list>
#include <string>
class Cat {
public:
Cat(const std::string& name) : m_name(name) {}
Cat() {}
virtual ~Cat() {}
public:
void setName(const std::string&) {}
const std::string& getName() const { return m_name; }
void eat(const std::list<std::string>& foods) {}
static void speak(const std::string& w) {}
//...
private:
std::string m_name;
};
// this is main.cpp
#include <fstream>
#include <iostream>
#include <sstream>
#include "cat.h"
#include "luaaa.hpp"
using namespace luaaa;
int main() {
lua_State* state = luaL_newstate();
luaL_openlibs(state);
// To export it:
LuaClass<Cat> luaCat(state, "AwesomeCat");
luaCat.ctor<std::string>();
luaCat.fun("setName", &Cat::setName);
luaCat.fun("getName", &Cat::getName);
luaCat.fun("eat", &Cat::eat);
// static member fuction was exported as Lua class member fuction.
// from Lua, call it as same as other member fuctions.
luaCat.fun("speak", &Cat::speak);
luaCat.def("tag", "Cat");
std::cout << "------------------------------------------" << std::endl;
std::stringstream buffer;
std::ifstream file("example.lua");
if (file) {
buffer << file.rdbuf();
file.close();
}
int err = luaL_loadbuffer(state, buffer.str().c_str(),
buffer.str().length(), "console");
if (err == 0) {
err = lua_pcall(state, 0, 0, 0);
}
if (err) {
std::cout << "lua err:" << lua_tostring(state, -1) << std::endl;
lua_pop(state, 1);
}
Cat xxx("zhangsan");
lua_getglobal(state, "onMessage");
if (lua_isfunction(state, -1)) {
LuaStack<Cat>::put(state, &xxx);
if (lua_pcall(state, 1, 0, 0) != 0) {
std::cerr << "Error calling function: " << lua_tostring(state, -1) << std::endl;
lua_close(state);
return -1;
}
} else {
std::cerr << "onMessage is not a function" << std::endl;
lua_close(state);
return -1;
}
lua_close(state);
return 0;
}
I made a PR of proposal implementation for method (2). #26
Thank you very much for the thoughtful feature request and for the clear explanation of your workflow. I appreciate the use case involving subfiles, and I agree that being able to reuse the project-level configuration in llmk.toml while temporarily building subsidiary files would be helpful for larger multi-file projects.
At the same time, one of the core design principles of llmk is that a project's build procedure should always remain reproducible and explicitly recorded in files, rather than depending on command-line arguments that leave no persistent trace. For this reason, llmk has intentionally avoided allowing “hidden” configuration through CLI options.
With that in mind, I think your proposal can still be supported if we restrict it to strictly temporary usage. The idea is as follows:
1. llmk.toml must always specify a source entry.
This defines the canonical reproducible build target for the project.
If source is missing, even --source=... on the command line will not be accepted.
2. A CLI option may temporarily override the source defined in the TOML, but only for the current invocation.
On every such invocation, llmk will emit a clear warning, e.g.:
warning: Overriding `source` from llmk.toml for this build.
This run is a temporary, non-reproducible override.
This makes the temporary and non-canonical nature of the override explicit.
This approach preserves reproducibility (the project always has a single, file-defined main source) while still allowing convenient one-off builds of subfiles during development.
I believe this balances the original design philosophy of llmk with the practical needs of users working on multi-file projects. I am happy to discuss further details or naming of the option, and I appreciate your input on making this feature useful without compromising the consistency of the tool.
Thanks again for the suggestion and for using llmk.
I completely respect and agree with your core idea behind this project’s design.
Your two suggestions make sense to me, and I am updating the PR accordingly (with the intention of squashing the commits later).
I think the option name should be a bit more deliberately inconvenient than the one in my PR at the moment, perhaps even excessively so, something like --do-not-use-this-option-override-source. One possible approach could be to allow a short option like -i (for "input," to avoid conflicting with --silent) and a longer option like --source, but only when used together with a flag such as --noncanonical.
Thank you for the follow-up and for your understanding.
Considering the balance between usability and llmk’s design philosophy, I would like to propose the following direction:
- Introduce
--source(with no short option) as the way to specify an alternative build target. - Require that any use of
--sourcemust also be accompanied by--temporary(short form-T).
Requiring --temporary also gives us a clean and extensible mechanism: if future requests arise to temporarily override other configuration fields, the same pattern can be reused without compromising reproducibility.
If this approach sounds reasonable to you, I’m happy to proceed with this direction.
Thanks again for the constructive dialogue and for refining the PR.
Thank you for the clarification and the concrete proposal. I think the suggested direction is very reasonable, and I am happy to proceed with it. I also understand the necessity of making -T extensible for future temporary functionalities, and I will try to implement the flag so that it meets that requirement.