-
Notifications
You must be signed in to change notification settings - Fork 48
Open
Description
Hi,
The following code behaves unexpectedly, probably because char** is ambiguous. It's an idiom in a codebase I am working with right now.
cppyy is at 3.5.0.
import cppyy
import cppyy.ll
cppyy.ll.set_signals_as_exception(True)
cppyy.cppdef("""
struct MyTestStruct
{
char** name;
};
std::string theName = "This is a test";
char* theNameC = (char*)theName.c_str();
auto stc = MyTestStruct();
stc.name = &theNameC;
""")
print(cppyy.gbl.stc.name) # <cppyy.LowLevelView object at ...>
cppyy.gbl.std.string(cppyy.gbl.stc.name[0]) # I would expect string to be constructed, but instead it segfaults*** Break *** segmentation violation
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[21], line 1
----> 1 cppyy.gbl.std.string(cppyy.gbl.stc.name[0])
TypeError: Template method resolution failed:
none of the 13 overloaded methods succeeded. Full details:
string::string(std::initializer_list<char> __il, const std::allocator<char>& __a) =>
TypeError: takes at least 2 arguments (1 given)
string::string(std::initializer_list<char> __il) =>
SegmentationViolation: segfault in C++; program state was reset
string::string(std::string&& __str, const std::string::allocator_type& __a) =>
TypeError: takes at least 2 arguments (1 given)
string::string(std::string&& __str) =>
TypeError: could not convert argument 1
string::string(const std::string::allocator_type& __a) =>
TypeError: could not convert argument 1
string::string(const std::string& __str, const std::string::allocator_type& __a) =>
TypeError: takes at least 2 arguments (1 given)
string::string() =>
TypeError: takes at most 0 arguments (1 given)
string::string(const std::string& __str) =>
TypeError: could not convert argument 1
string::string(const char* __s, std::string::size_type __n, const std::allocator<char>& __a) =>
TypeError: takes at least 3 arguments (1 given)
string::string(const char* __s, std::string::size_type __n) =>
TypeError: takes at least 2 arguments (1 given)
string::string(const std::string& __str, std::string::size_type __pos, const std::allocator<char>& __a = std::allocator<char>()) =>
TypeError: takes at least 2 arguments (1 given)
string::string(const std::string& __str, std::string::size_type __pos, std::string::size_type __n, const std::allocator<char>& __a = std::allocator<char>()) =>
TypeError: takes at least 3 arguments (1 given)
string::string(std::string::size_type __n, char __c) =>
TypeError: takes at least 2 arguments (1 given)
string::string(const char* __s) =>
TypeError: could not convert argument 1 (bad argument type for built-in operation)
Naturally, I tried cppyy.ll.cast["char**"](cppyy.gbl.stc.name), but:
TypeError: Could not find "cppyy_cast<char**>" (set cppyy.set_debug() for C++ errors):
none of the 3 overloaded methods succeeded. Full details:
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
none of the 4 overloaded methods succeeded. Full details:
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
char** __cppyy_internal::cppyy_cast(char* val) =>
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
Of course, this can be worked around with a pythonization:
from ctypes import POINTER, c_char_p
def replace_name(cls, name):
if name != "MyTestStruct":
return
cls._name = cls.__dict__["name"]
def name_impl(self):
return cppyy.gbl.std.string(POINTER(c_char_p).from_address(cppyy.ll.addressof(self._name[0]))[0])
cls.name = property(name_impl)
cppyy.py.add_pythonization(replace_name, "")Is there a better way around this?
Metadata
Metadata
Assignees
Labels
No labels