From: William S F. <ws...@fu...> - 2009-11-24 21:42:59
|
Russell E. Owen wrote: > In article <4AE...@fu...>, > William S Fulton <ws...@fu...> wrote: > > > On Nov 1, 2009, at 12:59 PM, William S Fulton wrote: > >> Russell E. Owen wrote: >>> I am having some issues with shadowed constructors that I think are caused >>> by >>> using std_vector.i >>> Some of our classes have multiple constructors such as this: >>> Foo::Foo(std::vector<double> &values) >>> Foo::Foo(std::vector<boost::shared_ptr<FancyClass> > &fancyClasses) >>> and our SWIG file wraps the class Foo and also wraps the arguments as so: >>> %template(VectorDouble) std::vector<double>; >>> %template(VectorFancyClass)std::vector<boost::shared_ptr<FancyClass> >; >>> SWIG complains that the latter constructor is shadowed by the former. >>> As far as I can tell this is because both std::vector<double> and >>> std::vector<boost::shared_ptr<some fancyclass> > have been templated after >>> including std_vector.i. Thus SWIG is trying to support all of the following >>> forms of Foo constructor: >>> 1) an explicitly constructed VectorDouble >>> 2) a python list of doubles (due to std_vector.i and much appreciated) >>> 3) an explicitly constructed VectorFancyClass >>> 4) a python list of FancyClasses (due to std_vector.i and not necessary) >>> and the two python list versions (2 and 4) are colliding with each other. >>> I suspect that both Foo constructors are actually available, and that only >>> case (4) is unavailable. If so, we can live with it. But I would rather >>> explicitly disable std_vector.i for VectorFancyClass if there is some easy >>> way to do this. >>> I realize I could just include std_vector.i at the very end, but that >>> happens >>> to be a headache due to the way we're including it right now (in a common >>> .i >>> file shared by all others -- maybe that is a mistake). >>> Anyone have any suggestions? >> I don't see why SWIG is doing this and I can't replicate this problem. I >> suggest you post a complete standalone example demonstrating it... > > Here is my example (slightly longer than you requested, but short > enough, I trust, to serve) > > *** swigtest.h *** > > #include <iostream> > #include <vector> > > namespace test { > class Bar { > public: > explicit Bar::Bar(int val=0) : intVal(val) {}; > int intVal; > }; > > class Foo { > public: > explicit Foo::Foo(std::vector<int> const &intVec) { > std::cout << "Foo("; > for (size_t ind = 0; ind < intVec.size(); ++ind) > std::cout << intVec[ind] << ", "; > std::cout << ") constructor" << std::endl; > } > explicit Foo::Foo(std::vector<Bar> const &barVec) { > std::cout << "Foo("; > for (size_t ind = 0; ind < barVec.size(); ++ind) > std::cout << "Bar(" << barVec[ind].intVal << "), "; > std::cout << ") constructor" << std::endl; > } > }; > > } > > *** swigtest.i *** > > %module swigtest > %{ > #include "swigtest.h" > %} > > %include "std_vector.i" > %template(IntVec) std::vector<int>; > %template(BarVec) std::vector<test::Bar>; > %include "swigtest.h" > > > *** runtest.py *** > > #!/usr/bin/env python > # run swigtest > > import swigtest > > # these should work > iv = swigtest.IntVec() > iv.append(1) > iv.append(2) > iv.append(3) > swigtest.Foo(iv) > > swigtest.Foo([1, 2, 3]) > > bv = swigtest.BarVec() > bv.append(swigtest.Bar(1)) > bv.append(swigtest.Bar(2)) > bv.append(swigtest.Bar(3)) > swigtest.Foo(bv) > > swigtest.Foo([swigtest.Bar(1), swigtest.Bar(2), swigtest.Bar(3)]) > > # this is commented out because it aborts or send Foo garbage > # it may or may not be relevant to the problem being discussed > # I suspect the abort or garbage is a swig bug in any case > #swigtest.Foo([1, 2, swigtest.Bar(3)]) > #swigtest.Foo([swigtest.Bar(1), swigtest.Bar(2), 3]) > > When I build it I get a warning about a shadowed method (see appended > log). But when I run the test code it works as desired. > > > > I also found that if I simply move the swigtest.i line: > %template(BarVec) std::vector<test::Bar>; > after the line: > %include "swigtest.h" > then the problem goes away (though one can no longer provide a plain > python list of Bar). Also it solves the problem from the commented-out > lines of the test code: instead of aborting or sending Foo garbage, swig > correctly detects the mixed type list and rejects it! > Yes, it is better to use %template with a class type (Bar in this case) once SWIG has parsed. > I would prefer a solution that allows a plain list of Bar and correctly > rejects lists of mixed types. But barring such a solution, simply > templating the list of Bar at the end will do. > swig-1.3.37 has a fix for this problem, as per the CHANGES entry: 2008-11-28: wsfulton [UTL] Fix #2080497. Some incorrect acceptance of types in the STL, eg a double * element passed into a vector<int *> constructor would be accepted, but the ensuing behaviour was undefined. Now the type conversion correctly raises an exception. I tried the latest version using your commented out lines above passing in vectors of mixed types and get: Foo(1, 2, 3, ) constructor Foo(1, 2, 3, ) constructor Foo(Bar(1), Bar(2), Bar(3), ) constructor Foo(Bar(1), Bar(2), Bar(3), ) constructor Traceback (most recent call last): File "./runme.py", line 26, in <module> example.Foo([1, 2, example.Bar(3)]) File "/home/william/swig/trunk/Examples/william/temp9/example.py", line 217, in __init__ this = _example.new_Foo(*args) NotImplementedError: Wrong number of arguments for overloaded function 'new_Foo'. Possible C/C++ prototypes are: test::Foo(std::vector< int,std::allocator< int > > const &) test::Foo(std::vector< test::Bar,std::allocator< test::Bar > > const &) PS I also had to correct this problem in the constructors, but I don't think it will affect the SWIG output: g++ -c -fpic example_wrap.cxx example.cxx -I/usr/include/python2.5 -I/usr/lib/python2.5/config In file included from example_wrap.cxx:2801: swigtest.h:8: error: extra qualification ‘test::Bar::’ on member ‘Bar’ swigtest.h:14: error: extra qualification ‘test::Foo::’ on member ‘Foo’ swigtest.h:20: error: extra qualification ‘test::Foo::’ on member ‘Foo’ |