Open jak6jak opened 1 year ago
Using const char*
is difficult b/c ownership isn't clear from reflection only and b/c Python's strings are unicode, not single byte chars. Thus, for example, using std::string_view
like above has no zero-copy benefits: the Python unicode needs to be converted anyway (assumes UTF-8 by default) and some buffer needs to be managed (cppyy actually does this for std::string_view
). Also str("Bob")
gives the same type as "Bob"
but at the cost of another superfluous copy.
The only way to get the same level of control over const char*
buffers as in C, however, is to use Python's ctypes
, which cppyy accepts for function arguments, variables, etc., and to pick your encoding or use Python's bytes
type.
As for the templates, make sure that the template arguments can actually be deduced, or specify them explicitly using []
. I'd be surprised if the template argument types are const char*
, though. But if they are, yes, cppyy does not try that possibility automatically: it will default to std::string
.
I'm not otherwise familiar with flecs.
okay I think I understand what you are saying. entity is defined as thus:
/** Create an entity.
*
* \memberof flecs::world
* \ingroup cpp_entities
*/
template <typename... Args>
flecs::entity entity(Args &&... args) const;
I have modified my code to be this:
def hello_world():
#print(dir(flecs.world))
cppyy.ll.set_signals_as_exception(True)
with cppyy.ll.signals_as_exception():
world = flecs.world(cppyy.gbl.ecs_init())
e = world.entity["const char *"](cppyy.ctypes.c_char_p(bytes("Bob","ascii")))
print(e.is_alive())
print(e.name())
g = world.lookup("Bob")
print(g.name(), "Look up")
it seems a bit verbose but it works as far as I can tell. Am I doing anything redundant or misunderstanding anything?
Well, I'm not exactly following. If the declaration of entity
is simply as above, than it should "just work". Example:
import cppyy
cppyy.cppdef(r"""\
class World {
public:
template <typename... Args>
std::string entity(Args&&... args) const {
std::ostringstream o;
((o << args << ' '),...);
return o.str();
}
};""")
world = cppyy.gbl.World()
print(world.entity("Bob"))
print(world.entity("Bob", "Alice"))
But do note that the above does not require any const char*
. If you print the doc after the calls:
print(world.entity.__doc__)
you'll see that the template is instantiated with std::string
's, not const char*
's.
So, my best guess is that there is something in the implementation body of entity
that absolutely requires these to be C strings (or otherwise runs in to SFINAE and a silent error). That might also explain why you see different behaviors for different types across different functions, depending on what happens to "fit."
And yes, this:
import ctypes
print(world.entity["const char*"](ctypes.c_char_p(bytes("Bob","ascii"))))
also works with the example above, but it's not necessary.
That said, supplying either ctypes.c_char_p(bytes("Bob","ascii")
or ["const char*"]
alone doesn't seem to work (for different reasons each), which is something that I can fix. In particular, supporting this world.entity["const char*"]("Bob")
is easily done (just under the assumptions that a) UTF-8 is fine and b) no pointer to the buffered C string is stored).
I pushed some fixes to the repo to make both usage of world.entity["const char*"]("Bob")
and world.entity(ctypes.c_char_p(bytes("Bob","ascii")))
behave as expected.
The fixes mentioned above a released with cppyy 3.0.0 and its dependencies.
I am using cppyy to create bindings for flecs: https://github.com/SanderMertens/flecs which is a C library with a C++ interface option. Unfortunately, this library is an avid user of const char * strings. Sometimes I am able to use string_view other times that does not work. Here is some simple code I am trying to get to work:
I am confused on how I should be passing and using strings for methods and classes that require const char *. right now it seems pretty inconsistent on what I should be using.