C++에서 선언한 enum class의 이름 그대로 Lua 스크립트에서 번거롭지 않은 느낌에 사용하고 싶다 (C++/Boost/Sol/Siv3D)

7710 단어 C++루아Siv3D

무엇을 원하십니까?


enum class MyEnum {
    A,
    B,
    C,
}

이런 enum class가 있었기 때문에 Lua에서
local e = MyEnum.B

라는 느낌으로 사용하고 싶다.
하지만 일일이 Lua 측에서 MyEnum={}; MyEnum.A=0; MyEnum.B=1; ... 같은 것을 수작업으로 하고 싶지 않다.

접근


  • 매크로를 사용하여 어떻게 든
  • 열거 형 숫자 및 문자열 맵을 제공하고 C++ 측에서 Lua 변수를 설정합니다.
  • 이 기사를 참고로 했습니다
  • h tp // w w. Shingu r Poin t. 오 rg / b ぉ g / c / c
  • htp // k 료자히로. 는 bぉ. jp/엔트리/2015/09/13/202702
  • 공부가 되었습니다.


  • 소스 코드



    개발 환경:
  • Windows 10
  • Visual Studio Community 2015 Update3
  • Boost 1.60.0 (bimap이 편리했기 때문에)
  • Lua 5.2.4
  • Sol 2.17.3

  • Siv3D August 2016 v2 (문자열 처리가 편리하기 때문에)
  • #include <Siv3D.hpp>
    #include <boost/bimap/bimap.hpp>
    #include <sol.hpp>
    #pragma comment(lib, "lua52.lib")
    
    #define ENUM_CLASS(NAME, ...) \
    enum class NAME : int { __VA_ARGS__ }; \
    struct NAME##_ { \
        using bimap_t = boost::bimaps::bimap<NAME, String>; \
        using value_t = bimap_t::value_type; \
        using enum_t = NAME; \
        template <class T> static String toString(const T v) { return bimap_holder::get().left.at((NAME)v); } \
        static auto toEnum(const String& v) { return bimap_holder::get().right.at(v); } \
        static const size_t size() { return bimap_holder::get().size(); } \
        static const String name() { return Widen(#NAME); } \
        template <class Fn> static void forEach(Fn f) { \
            using iterator = bimap_t::left_const_iterator; \
            for (iterator it = bimap_holder::get().left.begin(); it != bimap_holder::get().left.end(); it++) { \
                f(it->first, it->second); \
            } \
        } \
    private: \
        struct bimap_holder { \
            static bimap_t& get() { \
                static bimap_t m_; \
                static bool init = false; \
                if (!init) { \
                    init = true; \
                    initialize(); \
                } \
                return m_; \
            } \
        }; \
        static void initialize() { \
            bimap_t& m = bimap_holder::get(); \
            Array<String> arr = Widen(#__VA_ARGS__).split(L','); \
            int enum_val = 0; \
            for (auto s : arr) { \
                Array<Match> match = Regex::Search(s, L"\\s*=\\s*(.+)$"); \
                if (!match.empty()) { \
                    enum_val = Parse<int>(match[0].str(1)); \
                } \
                m.insert(value_t((NAME)enum_val, Regex::ReplaceAll(s, L"\\s*=.+$", L"").trim())); \
                ++enum_val; \
            } \
        } \
    };
    
    template <class Enum>
    void registerEnum(sol::state& lua)
    {
        lua[Enum::name().str()] = lua.create_table();
        Enum::forEach([&](Enum::enum_t e, String s) {
            lua[Enum::name().str()][s.str()] = (int)e;
        });
    }
    
    // enum class TestEnum の宣言
    // このようにする:
    ENUM_CLASS(TestEnum,
        A = 100,
        B,
        C,
        D,
        X,
        Y,
        Z);
    
    
    void Main()
    {
        // Lua初期化
        sol::state lua;
        lua.open_libraries();
    
        // Luaの環境にenumの値を設定
        registerEnum<TestEnum_>(lua);
    
        // Lua スクリプトで TestEnum.B という書き方ができる
        lua.script("function f() return TestEnum.B end");
    
        Println((int)(lua["f"]())); // => 101 (TestEnum::B)
    
        WaitKey();
    }
    

    실행 결과





    잡기


  • enum class A에 대해 A_라는 클래스가 생겨 버리는 곳이 기분 나쁠지도 모른다
  • bimap을 사용하지 않고 std::map으로 find 할 수 있습니다.
  • Sol이 string과 wstring을 좋은 느낌으로 마음대로 변환해주기 때문에 s3d::String 을 Narrow() 하지 않아도 된다
  • 좋은 웹페이지 즐겨찾기