ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.06k stars 492 forks source link

Binding a member function that returns a std::map does not compile, while returning a std::vector does #1515

Open OndrejPopp opened 11 months ago

OndrejPopp commented 11 months ago

Hello, here I am again! And this time with a Phd test case, ThePhd.h.txt

/*
    SPDX-FileCopyrightText: 2023 Ondrej Popp
    SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

#pragma once

#include <lua.hpp>

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <string>
#include <vector>
#include <map>

class ThePhd
{
 public:
    ThePhd() = default;

    const std::vector<std::string>& thePhdVector() const
    {
        return m_thePhdVector;
    } 

    const std::map<std::string, std::string>& thePhdMap() const
    {
        return m_thePhdMap;
    }

 private:
    std::vector<std::string> m_thePhdVector;

    std::map<std::string, std::string> m_thePhdMap;
};

void bindThePhd(sol::table& t)
{
    t.new_usertype<ThePhd>("ThePhd",
     sol::constructors<ThePhd()>(),

    // this one does compile,
    "thePhdVector", &ThePhd::thePhdVector,

    // while this one does not,
    "thePhdMap", &ThePhd::thePhdMap,

    // but this one does
    "wrapThePhdMap", [](const ThePhd& self)
      {return sol::as_table_t<std::map<std::string, std::string>>(self.thePhdMap());}
   ); 
}

As commented here above, while trying to bind the Phd, binding thePhdVector does compile, while binding thePhdMap does not. However, when you wrap that inside a sol::as_table_t it does compile, which is a good workaround, but I think the standard binding should work as well for the Phd?

And here is the compiler trace, thePhdTrace.txt

It appears to be failing around here,

/src/Multimedia/VideoEditors/OpenIO/OpenIo/Cxx/Bridges/Lua/Sol/OpenIo/Tree/ThePhd.h:40:27:   required from here
/usr/local/include/sol/usertype_container.hpp:1191:46: error: unable to deduce ‘auto&’ from ‘i.sol::container_detail::usertype_container_default<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >, void>::iter::it’
 1191 |                                 auto& it = i.it;
      |                                            ~~^~
/usr/local/include/sol/usertype_container.hpp:1191:39: note:   couldn’t deduce template parameter ‘auto’
 1191 |                                 auto& it = i.it;
      |                                       ^~
/usr/local/include/sol/usertype_container.hpp:1192:47: error: ‘struct sol::container_detail::usertype_container_default<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >, void>::iter’ has no member named ‘end’
 1192 |                                 auto& end = i.end;
      |                                             ~~^~~

Ok, that was my Phd test case :) Tx, and have a nice day, Ondrej

midwitdev commented 9 months ago

Hello, I have the same problem. Very frustrating

OndrejPopp commented 9 months ago

Good morning! Well it's not that bad... You need to write these bindings anyway so it's not too much effort to wrap the map. In addition I have found that std::optional doesn't work either, so you need to return it from the lambda as well, but without wrapping it inside sol::as_table_t because that does not make sense for a std::optional. There could be more, but I don't remember that right now, I didn't feel like commenting on it all, so I would have to look at the code. In any case, I was able to fix everything that didn't work, generally by returning it from a lambda. So that's not all that bad...

Oh yeah, there is an other thing, from the top of my head, if I remember correctly, optional parameters in a constructor do not work either so you need to expand those. For example, if you have T::T(t1 a, t2 b, t3 c = d) you need to expand that into, sol::constructors<T(t1 a, t2 b),T(t1 a, t2 b, t3 c)>() and so on if you have more optional parameters in your constructor.

For the rest, it works like a charm, tx PhD! image

roman-orekhov commented 1 month ago

@OndrejPopp you can fix the offending lines like this

                auto& it = i.it();
                auto& end = i.sen();

it should compile. But in my case using pairs doesn't actually run through the std::map anyway.

OndrejPopp commented 1 month ago

@roman-orekhov Ok, tx! But yes, std::map uses pairs so if that doesn't work then you still need to wrap it...

btw, it.sen() should be it.end() ?

roman-orekhov commented 1 month ago

No, with it.end() it won't compile. sen in from sentinel

OndrejPopp commented 1 month ago

Ok. Tx.