swig / swig

SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.
http://www.swig.org
Other
5.97k stars 1.26k forks source link

problems with wrapped methods that take std::string as an argument #3124

Closed dan-mermelstein-pfizer closed 2 months ago

dan-mermelstein-pfizer commented 2 months ago

I'm having issues using methods from wrapped classes in python that take std::string as an argument. The string can be a ref, a const ref, or a pointer, they all fail the same.

I'm posting here the simplest example I can think of. I've taken the class example from the python sub directory of the Examples directory in the swig distribution, and added a method that takes a string as an argument:

class Shape {
public:
  Shape() {
    nshapes++;
  }
  virtual ~Shape() {
    nshapes--;
  }
  double  x, y;
  void    move(double dx, double dy);
  virtual double area() = 0;
  virtual double perimeter() = 0;
  static  int nshapes;
  std::string str;
  void setStr(std::string s) { str = s; }
};

class Circle : public Shape {
private:
  double radius;
public:
  Circle(double r) : radius(r) { }
  virtual double area();
  virtual double perimeter();
};

class Square : public Shape {
private:
  double width;
public:
  Square(double w) : width(w) { }
  virtual double area();
  virtual double perimeter();
};

The code appears to wrap fine, and builds fine, but when I try to call setStr from a shape object in python:

s = example.Square(10)
s.setStr("Hello")

I get

TypeError: in method 'Shape_setStr', argument 2 of type 'std::string'

indicating that some portion of the wrapped module didn't know what to do with the string argument.

I'm able to resolve this by adding %include to my interface file. However, this same issue extends to objects of other classes that I'm using as arguments, but for which I don't have access to the interface file. I was under the impression that swig could correctly wrap std::string without the need to explicitly include std_string.i, and I was wondering if I'm doing something wrong or have something borked in my environment that is somehow preventing proper typemapping.

my wrap and build process is:

swig -python -c++ example.i python setup.py build_ext --inplace

where example.i is:

/* File : example.i */
  %module example

  %{
  #include "example.h"
  %}

  %include "example.h"

and setup.py is

"""
 setup.py file for SWIG example
 """

  from distutils.core import setup, Extension

  example_module = Extension('_example',
                             sources=['example_wrap.cxx', 'example.cxx'],
                             )

  setup (name = 'example',
         version = '0.1',
         author      = "SWIG Docs",
         description = """Simple swig example from docs""",
         ext_modules = [example_module],
         py_modules = ["example"],
         )

I'm using swig 4.2.1 with MSVC version 14.38, running on windows with cygwin using python 3.10.

Thank you

ojwb commented 2 months ago

I was under the impression that swig could correctly wrap std::string without the need to explicitly include std_string.i

Your impression is essentially incorrect - without %include <std_string.i> SWIG will wrap std::string as an opaque type, which is unlikely to be what you want.

Manual says:

_The std_string.i library provides typemaps for converting C++ std::string objects to and from strings in the target scripting language._

So without std_string.i you won't get C++ std::string objects converted to and from strings in the target scripting language...

Closing as not a bug, but if you can see doc changes which would have made this clearer to you please propose by opening a PR.