gpt4 book ai didi

c++ - 在 Lua/Binding 中使用 C++ 函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:12:40 25 4
gpt4 key购买 nike

所以基本上我试图找到一种在 Lua 中使用不是 lua_CFunctions 的 C++ 函数的方法(不要返回和 int 并将 lua_State 作为参数)。基本上你的常规旧 C++ 函数。不过,问题是我正在尝试找到一种方法来做到这一点,而无需编写自己的专用 lua_CFunction(所以基本上想象我已经有一个 C++ 程序或一堆函数,我想在 Lua 中使用,但我没有'不想为每个人编写一个新函数)。

所以,假设我有一个非常简单的 C++ 函数:

static int doubleInt(int a) {
return a*2;
}

(有或没有静态,它不应该(?)重要)。

假设我想通过在 lua 脚本中调用 doubleInt(10) 在 Lua 中使用此函数。有没有办法在不单独写的情况下做到这一点
static int callFunc(lua_State *L) {
//do stuff to make the function work in lua
}

对于每个单独的功能?所以类似于 luaBind 对 def() 函数所做的事情(我知道这很糟糕,但我不能真正使用单独的专用绑定(bind)库;必须自己编写)。

我知道我必须为此编写一个带有模板的类,但我什至不知道如何在 Lua 中获取该函数。我认为 C++ 中没有一种方法可以自动生成自定义函数(大概在编译时)——这太棒了——所以我什至不知道从哪里开始。

最佳答案

这是一个非常开放的问题。

我最近一直在研究一个 lua 绑定(bind)库,所以我可以解释一下我是如何做到的,但是有很多方法可以做到。

您没有标记这个问题 C++11。但是,我将假设您使用的是 C++11。如果没有,那么这将非常困难,我会说完全不切实际,尤其是如果您对 boost::mpl 还不够了解的话。有一些想法如何去做。你绝对应该使用 luabind在这种情况下。

您需要的第一件事是,您需要创建一些基本的基础设施,告诉您如何将 C++ 类型转换为相应的 lua 类型并返回。

IMO 最好的方法是使用类型特征,而不是使用大量重载函数。因此,您将定义一个主模板:

namespace traits {

template <typename T>
struct push;

template <>
struct push<int> {
static void to_stack(lua_State * L, int x) { lua_pushinteger(L, x); }
};

template <>
struct push<double> {
static void to_stack(lua_State * L, double d) { lua_pushnumber(L, d); }
};

...

} // end namespace traits

等等。您可能还想将它专门用于 std::string诸如此类的事情。

然后你可以制作一个通用的 push像这样的功能:
template <typename T>
void push(lua_State * L, const T & t) {
traits::push<T>::to_stack(L, t);
}

这里的优点是调用 push 时不考虑隐式转换。 .您传递的类型与您为其定义特征的内容完全匹配,或者它失败。并且您不会在 double 之间遇到模棱两可的过载问题。和 int等等,这可能是一个很大的痛苦。

然后,你必须对 read 做同样的事情。 ,所以你有一个特征告诉你如何从堆栈中读取给定类型的值。您的 read技术需要以某种方式发出故障信号,您可以决定是否应该使用异常或不同的技术。

一旦你有了这个,你可以尝试制作 adapt模板将采用任意函数指针并尝试将其调整为 lua_CFunction这大致相同。

基本上,您想使用可变参数模板,以便您可以专门针对函数指针的所有参数。您将这些类型一一传递给您的读取方法,并使用索引序列从正确的堆栈位置读取。你尝试阅读它们,如果你能做到没有错误,那么你可以调用目标函数,然后返回它的结果。

如果您还想将通用 C++ 对象作为返回值推回,那么您可以在最后调用您的 push 函数。

首先,为了提供帮助,您需要一个“索引序列”工具。如果您在 C++14您可以使用 std::make_integer_sequence ,如果没有,那么你必须自己动手。我的看起来像这样:
namespace detail {

/***
* Utility for manipulating lists of integers
*/

template <std::size_t... Ss>
struct SizeList {
static constexpr std::size_t size = sizeof...(Ss);
};

template <typename L, typename R>
struct Concat;

template <std::size_t... TL, std::size_t... TR>
struct Concat<SizeList<TL...>, SizeList<TR...>> {
typedef SizeList<TL..., TR...> type;
};

/***
* Count_t<n> produces a sizelist containing numbers 0 to n-1.
*/
template <std::size_t n>
struct Count {
typedef
typename Concat<typename Count<n - 1>::type, SizeList<n - 1>>::type type;
};

template <>
struct Count<0> {
typedef SizeList<> type;
};

template <std::size_t n>
using Count_t = typename Count<n>::type;

} // end namespace detail

这是您的 adapt类可能看起来像:
// Primary template
template <typename T, T>
class adapt;

// Specialization for C++ functions: int (lua_State *, ...)
template <typename... Args, int (*target_func)(lua_State * L, Args...)>
class adapt<int (*)(lua_State * L, Args...), target_func> {

template <typename T>
struct impl;

template <std::size_t... indices>
struct impl<detail::SizeList<indices...>> {
static int adapted(lua_State * L) {
try {
return target_func(L, read<Args>(L, 1 + indices)...);
} catch (std::exception & e) {
return luaL_error(L, "Caught an exception: %s", e.what());
}
}
};

public:
static int adapted(lua_State * L) {
using I = detail::Count_t<sizeof...(Args)>;
return impl<I>::adapted(L);
}
};

我实现的真实代码是 here .我决定在不使用异常的情况下这样做。

这种技术也适用于编译时——因为您将函数指针作为非类型模板参数传递给任意 C++ 函数,而 adapt模板生成 lua_CFunction作为静态类成员,当您使用指向 adapt<...>::adapted 的指针时,它必须在编译时全部解决。这意味着编译器可以内联所有不同的位。

为了解决无法推断非类型模板参数的类型(如函数指针(C++17 之前))的问题,我使用了一个如下所示的宏:
 #define PRIMER_ADAPT(F) &::primer::adapt<decltype(F), (F)>::adapted

所以,我可以取一个复杂的 C++ 函数 f ,然后使用 PRIMER_ADAPT(&f)好像它只是一个 lua_CFunction .

您应该意识到,制作所有这些东西并对其进行测试需要很长时间。我在这个库上工作了一个多月,它是从另一个项目中的一些代码中重构出来的,在那里我对其进行了更长时间的改进。 lua 中也有很多与这样的“自动化”堆栈操作相关的陷阱,因为它不会为你做任何边界检查,你需要调用 lua_checkstack要严格正确。

您绝对应该使用现有的库之一,除非您有非常迫切的需要阻止它。

关于c++ - 在 Lua/Binding 中使用 C++ 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38429540/

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