如何在C ++中获取预加载的模块名称 [英] How to get preloaded module name in C++

查看:102
本文介绍了如何在C ++中获取预加载的模块名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有可能创建一个C ++函数来返回(或打印)当前脚本的预加载模块名称.

I wonder if it's possible to create a C++ function that returns(or prints) the preloaded module name of the current script.

例如,我想在以下代码中创建getModuleName()函数,以便运行代码可以将A打印为结果.

For example, I would like to create getModuleName() function in the following code so running the code can print A as a result.

#include "lua.hpp"

void main()
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_settop(L, 0);
    luaL_dostring(L, "package.preload['A'] = function ()\n"
                     "local a = {}\n"
                     "a.name = my.getModuleName()\n"
                     "print(a.name)\n"
                     "return a end");
    luaL_dostring(L, "require 'A'\n");
    lua_close(L);
}

如何在C ++中创建getModuleName()函数?

How can I create a getModuleName() function in C++?

如果C ++无法实现,我想知道是否可以在Lua中实现.

If it's not possible with C++, I would like to know if it's possible to do it in Lua.

P.S:我正在使用SWIG来绑定C ++代码.

P.S: I'm using SWIG for binding C++ code..

推荐答案

require调用名称为第一个参数的预加载函数.

require calls the preload function with the name it was given as the first argument.

#include "lua.hpp"

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_settop(L, 0);
    luaL_dostring(L, "package.preload['A'] = function(this)\n"
                     "local a = {}\n"
                     "a.name = this\n"
                     "print(a.name)\n"
                     "return a end");
    luaL_dostring(L, "require 'A'\n");
    lua_close(L);
}

$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 test.cpp -llua5.2
$ ./a.out 
A

避免传递和争论

我不知道您为什么要这样做,但是通过用您自己的版本覆盖require函数可以很容易地做到这一点.为了简单起见,我只显示Lua代码:

Avoiding to pass and argument

I don't see why you would want to do this but it is easily doable by overriding the require function with your own version. For simplicity I only show the Lua code:

local require_original = require
function require(name, ...)
    current_module = name
    local val = table.pack(require_original(name, ...))
    current_module = nil
    return table.unpack(val,1,val.n)
end

package.preload["test"] = function()
    print("While loading:", current_module)
    return {}
end

print("Before loading:", current_module)
require("test")
print("After loading:", current_module)

$ lua5.2 test.lua
Before loading: nil
While loading:  test
After loading:  nil


回答被误解的问题

package.preload只是一个常规的L​​ua表,您可以像从C-API来的任何其他Lua表一样遍历该表.在这种情况下,您将不得不遍历两次,一次以确定添加新的预紧力之前已经存在的预紧力,然后再一次添加预紧力.


Answer to the misunderstood question

package.preload is just a regular Lua table which you can traverse just as any other Lua table from the C-API. In this case you will have to traverse it twice, once to determine which preloads are already there before adding a new one, and then again after you added your preload.

#include <iostream>
#include <string>
#include <unordered_set>

#include "lua.hpp"

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_settop(L, 0);

    // Determine all existing preloads
    std::unordered_set<std::string> known_preloads;
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "preload");
    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        known_preloads.emplace(lua_tostring(L, -2)); // pops key
        lua_pop(L, 1); // pops value
    }
    lua_pop(L, 2); // pop preload and package

    // Add a new preload
    luaL_dostring(L, "package.preload['A'] = function ()\n"
                     "local a = {}\n"
                     "a.name = my.getModuleName()\n"
                     "print(a.name)\n"
                     "return a end");
    luaL_dostring(L, "require 'A'\n");

    // Determine which preloads are new
    std::unordered_set<std::string> new_preloads;
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "preload");
    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        std::string current = lua_tostring(L, -2); // pops key
        if (known_preloads.find(current) == known_preloads.end()) {
            new_preloads.emplace(current);
        }
        lua_pop(L, 1); // pops value
    }
    lua_pop(L, 2); // pop preload and package

    // Print the new preloads
    for (auto const & preload : new_preloads) {
        std::cout << preload << '\n';
    }

    lua_close(L);
}


您可能要考虑使用 Sol2 .它是现有的用于C ++的Lua C-API最快的包装器.它需要C ++ 14,这是完全值得的.看看我如何一次都不必担心堆栈!


You might want to consider using Sol2. It's the fastest wrapper around the Lua C-API for C++ that exists. It requires C++14 and it's totally worth it. See how I didn't worry about the stack a single time!

#include <iostream>
#include <string>
#include <unordered_set>

#define SOL_CHECK_ARGUMENTS 1
#include "sol.hpp"

int main() {
    sol::state L;
    L.open_libraries();

    // Determine all existing preloads
    std::unordered_set<std::string> known_preloads;
    L.get<sol::table>("package").get<sol::table>("preload").for_each(
        [&](sol::object &key, sol::object &) {
            known_preloads.emplace(key.as<std::string>());
        });

    // Add a new preload
    L.script("package.preload['A'] = function ()\n"
             "local a = {}\n"
             "a.name = my.getModuleName()\n"
             "print(a.name)\n"
             "return a end");
    L.script("require 'A'\n");

    // Determine which preloads are new
    std::unordered_set<std::string> new_preloads;
    L.get<sol::table>("package").get<sol::table>("preload").for_each(
        [&](sol::object &key_, sol::object &) {
            std::string key = key_.as<std::string>();
            if (known_preloads.find(key) == known_preloads.end()) {
                new_preloads.emplace(key);
            }
        });

    // Print the new preloads
    for (auto const & preload : new_preloads) {
        std::cout << preload << '\n';
    }
}

这篇关于如何在C ++中获取预加载的模块名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆