Как зарегистрировать шаблонную функцию в LuaBridge?

Я новичок в Lua и LuaBridge и пытаюсь выяснить, можно ли зарегистрировать шаблонную функцию? Я посмотрел в Интернете и через руководство LuaBridge безрезультатно. Я попытался создать указатель на базовый класс, но потом выяснил, что в Lua нет способа привести его в действие. Если у кого-то есть какие-либо идеи о том, как решить эту проблему, мы будем благодарны.

template<typename T>
T* GetComponentByType()
{
    try
    {
        for (ComponentVectorWrapper::t_Component_Iter iter = m_Components_.begin(); iter != m_Components_.end(); ++iter)
            if (*iter != nullptr)
                if (T* type = dynamic_cast<T*>(*iter))
                    return type;
        throw ComponentMissingException();
    }
    catch (ComponentMissingException& e)
    {
        std::cout << e.what() << std::endl;
        __debugbreak();
    }
}

Component* getComponentByType(std::string type)
{
    if (type == "Transform")
        return GetComponentByType<TransformComponent>();

    return nullptr;
}

static void registerLua(lua_State* L)
{
    using namespace luabridge;

    getGlobalNamespace(L)
        .beginClass<GameObject>("GameObject")
        .addConstructor<void(*)(const char* name)>()
        .addData<const char*>("name", &GameObject::m_Name_, false)
        .addData<TransformComponent*>("transform", &GameObject::m_Transform)
        .addFunction("addComponent", &GameObject::registerComponent)
        .addFunction("getComponent", &GameObject::getComponentByType)
        .addFunction("removeComponent", &GameObject::removeComponent)
        .endClass();
}

Решение

Забыл опубликовать это ранее, но решение состоит в том, чтобы определить тип из строки, оттуда вам нужно установить глобальный в Lua, а затем вернуть ссылку на этот глобальный.

luabridge::LuaRef GameObject::luaGetComponent(std::string type)
{
    // Return component
    return luaGetComponentHelper(type, false, "");
}

luabridge::LuaRef GameObject::luaGetComponentHelper(std::string type, bool findAll, const char* tag)
{
    lua_State* L = (&LuaEngine::getInstance())->L();

    // Find component type
    if (type == "TransformComponent")
        LuaHelper::GetGlobalComponent<TransformComponent>(*this, findAll, m_CompName, tag);
    else if (type == "CameraComponent")
        LuaHelper::GetGlobalComponent<CameraComponent>(*this, findAll, m_CompName, tag);
    else if (type == "FirstPersonCameraComponent")
        LuaHelper::GetGlobalComponent<FirstPersonCameraComponent>(*this, findAll, m_CompName, tag);
    else if (type == "RenderComponent")
        LuaHelper::GetGlobalComponent<RenderComponent>(*this, findAll, m_CompName, tag);
    else if (type == "ThirdPersonCameraComponent")
        LuaHelper::GetGlobalComponent<ThirdPersonCameraComponent>(*this, findAll, m_CompName, tag);
    else if (type == "CanvasComponent")
        LuaHelper::GetGlobalComponent<CanvasComponent>(*this, findAll, m_CompName, tag);
    else if (type == "RigidBody")
        LuaHelper::GetGlobalComponent<RigidBody>(*this, findAll, m_CompName, tag);
    else if (type == "BoxCollider")
        LuaHelper::GetGlobalComponent<BoxCollider>(*this, findAll, m_CompName, tag);
    else
    {
        luabridge::setGlobal(L, nullptr, m_CompName); // Prevents errors
        LuaEngine::printError("Component not found.");
    }

    // Return component
    return luabridge::getGlobal(L, m_CompName);
}

template<typename T>
static luabridge::LuaRef GetGlobalComponent(GameObject& go, bool findAll, const char* globalName, const char* tag)
{
    // Get lua state
    auto L = LuaEngine::getInstance().L();

    // Register global
    if (findAll)
    {
        auto vec = go.GetComponentsByType<T>();
        // Check for tag
        if (tag != "")
        {
            // Find by tag
            std::vector<T*> elements;

            for (auto& e : vec)
            {
                if (static_cast<Component*>(e)->getTag() == tag)
                    elements.push_back(e);
            }

            luabridge::setGlobal(L, LuaHelper::ToTable(elements), globalName);
        }
        else
            luabridge::setGlobal(L, LuaHelper::ToTable(vec), globalName);
    }
    else
        luabridge::setGlobal(L, go.GetComponentByType<T>(), globalName);

    return luabridge::getGlobal(L, globalName);
}

1 ответ

Вы не можете зарегистрировать шаблонную функцию. Вы должны зарегистрировать явные экземпляры.

#include <iostream>
#include <lua.hpp>
#include <LuaBridge.h>

char const script [] =
  "local t = Test()"
  "t:test_int(123)"
  "t:test_str('Hello')";

class Test
{
public:
  template < typename T >
  void test(T t) { std::cout << t << '\n'; }
};

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

  luabridge::getGlobalNamespace(L)
    .beginClass<Test>("Test")
      .addConstructor<void(*)(void)>()
      .addFunction("test_int", &Test::test<int>)
      .addFunction("test_str", &Test::test<char const *>)
    .endClass();

  if ( luaL_dostring(L, script) != 0)
    std::cerr << lua_tostring(L,-1) << '\n';
}

Я бы предложил вам использовать sol2, который не имеет такого ужасного синтаксиса (хотя нужен C++14).

#include <iostream>
#include <string>
#include <sol.hpp>

char const script [] =
  "local t = Test.new()"
  "t:test_int(123)"
  "t:test_str('Hello')";

class Test
{
public:
  template < typename T >
  void test(T t) { std::cout << t << '\n'; }
};

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

  L.new_usertype<Test>("Test",
    "test_int", &Test::test<int>,
    "test_str", &Test::test<std::string>
    );

  L.script(script);
}
Другие вопросы по тегам