I use swig to wrap c++ classes to ruby code. Some of my classes return std:vector of other classes so I use the std_vector.i for that.
%include "std_vector.i"
namespace std {
%template(VectorString) vector<string>;
%template(VectorField) vector<TruckBoris::Field>;
%template(VectorStructure) vector<TruckBoris::Structure>;
%template(VectorEnum) vector<TruckBoris::Enum>;
}
For the classes Enum and Structure I have this kind of warnings:
parser.cpp:2781:9: warning: destination for this 'memset' call is a pointer to dynamic class 'TruckBoris::Enum'; vtable pointer will be overwritten [-Wdynamic-class-memaccess]
memset(v_def,0,sizeof(Type));
^
parser.cpp:2807:66: note: in instantiation of member function 'swig::traits_as<TruckBoris::Enum, swig::pointer_category>::as' requested here
return traits_as< Type, typename traits< Type >::category >::as(obj, te);
^
parser.cpp:4236:92: note: in instantiation of function template specialization 'swig::as<TruckBoris::Enum>' requested here
std::vector<TruckBoris::Enum,std::allocator< TruckBoris::Enum > >::value_type val = swig::as<std::vector<TruckBoris::Enum,std::allocator< TruckBoris::Enum > >::value_type>( elem...
^
parser.cpp:2781:9: note: explicitly cast the pointer to silence this warning
memset(v_def,0,sizeof(Type));
^
(void*)
This is just some warnings and my extension is compiling and working as expected. But if there are some warnings I think it means that maybe I am wrong somewhere.
For informations:
I don't have warnings from simple classes like field but I have warning form Enum and Structure classes which both inherit from the same class. Here is the code:
class TagDeclaration
{
public:
TagDeclaration(clang::TagDecl * var);
~TagDeclaration(){}
void setPtr(clang::TagDecl * var); //for ruby interface
clang::TagDecl * getPtr() const; //for ruby interface
std::string getName() const;
bool hasNameForLinkage()const;
bool hasLinkage() const;
std::string getTypedefName() const;
std::string getRaw( clang::SourceManager & sm, const clang::LangOptions & lopt) const;
virtual TagDeclaration& Equals( const TagDeclaration & tag);
protected:
clang::TagDecl * m_var;
};
class Structure : public TagDeclaration
{
public:
Structure();
Structure(clang::TagDecl * var);
~Structure() {}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
virtual Structure& Equals(const Structure& tag);
#pragma clang diagnostic pop
std::string getTagType() const;
int getFieldsNumber() const;
std::vector<Field> getFields() const;
clang::FieldDecl * getField(int i) const;
private:
std::string m_tagType;
};
Edit :
I can reproduce this kind of error with this:
test.h
class Number {
public:
Number()
{
m_num = 0;
}
Number(int a): m_num(a) {}
~Number() {}
virtual void equals(){}
private:
int m_num;
};
class Float : public Number{
public:
Float(): Number() {}
Float(int a): Number(a) {}
~Float() {}
virtual void equals() {}
void printToto(){}
};
class Double : public Number {
public:
Double(): Number() {}
Double(int a): Number(a) {}
~Double() {}
virtual void equals() {}
void printTata();
};
test.i
%module "test"
%include "std_vector.i"
%{
#include "test.h"
%}
namespace std {
%template(VectorFloat) vector<Float>;
};
%include "test.h"
extconf.rb
require "mkmf"
CONFIG['CXX']='clang++'
create_makefile("test")
Related
Consider following piece of code:
template.h
template<typename T>
class templ{
public:
virtual const int virtualMethod(const T *const) const = 0;
}
Base.h
#include "template.h"
class Der1;
class Der2;
class Base :
public templ<Base>,
public templ<Der1>,
public templ<Der2>{
public:
virtual ~Base(){}
};
Der1.h
#include "Base.h"
class Der1 : public Base {
public:
virtual const int virtualMethod(const Base *const) const override;
virtual const int virtualMethod(const Der1 *const) const override;
virtual const int virtualMethod(const Der2 *const) const override;
};
Der1.cpp
#include "Der1.h"
const int Der1::virtualMethod(const Base *const sth) const{
return sth->templ<Der1>::virtualMethod(this);//does not work
//how to fix it?
}
const int Der1::virtualMethod(const Der1 *const sth) const{
//do sth
}
const int Der1::virtualMethod(const Der2 *const sth) const{
//do sth
}
Class Der2 also inherits from Base and implements these three functions.
For this code compiler gives me these messages:
'templ' is ambiguous ' Candidates are: templ() templ(const
templ &) templ() templ(const templ &) templ()
templ(const templ &) '
Function 'virtualMethod' could not be resolved
Namespace member function 'virtualMethod' cannot be resolved.
Type 'Der1' cannot be resolved.
undefined reference to
`templ::virtualMethod(Der1 const*) const'
In general, the idea of the code was to implement double type dispatch. Although I think I know what causes problems, I have no idea how to solve it. So maybe you can help me.
I am a little confused what was your intention...
But what about:
const int Der1::virtualMethod(const Base *sth) const {
return dynamic_cast<const templ<Der1> *>(sth)->virtualMethod(this);
}
I am a C++ noob and I have a noob question.
I have an abstract tree class definition in a header file. I know it is abstract because it contains virtual methods. It looks like so:
//AbsTree.h
class AbsTree {
public:
AbsTree();
virtual ~AbsTree() =0;
virtual void accept(Visitor &visitor) const = 0;
virtual void execute(Env &ctxt) const throw (InappropriateFunction);
};
class Operation: public AbsTree{
public:
Operation(char oper);
virtual ~Operation();
virtual void accept (Visitor &visitor) const;
char getOperator() const;
private:
char operator;
};
I have come up with the following implementation of this AbsTree:
AbsTree.cpp
#include "AbsTree.h"
AbsTree::AbsTree() {}
AbsTree::~AbsTree() {}
AbsTree::accept(Visitor &visitor) const{}
AbsTree::execute(Env &ctxt) const {}
Operation::Operation(char oper): operator(oper) {}
Operation::~Operation(){}
Operation::accept(Visitor &visitor) const{}
char Operation::getOperator() {
return operator;
}
So I try to compile the .cpp via:
g++ AbsTree.cpp -o AbsTree
and I get
AbsTree.cpp:3:1: error: 'AbsTree' does not name a type
AbsTree.cpp:4:1: error: 'AbsTree' does not name a type
AbsTree.cpp:5:1: error: 'AbsTree' does not name a type
AbsTree.cpp:6:1: error: 'AbsTree' does not name a type
AbsTree.cpp:8:1: error: 'Operation' does not name a type
AbsTree.cpp:9:1: error: 'Operation' does not name a type
AbsTree.cpp:10:1: error: 'Operation' does not name a type
AbsTree.cpp:11:6: error: 'Operation' has not been declared
AbsTree.cpp: In function 'char getOperator()':
AbsTree.cpp:12:9: error: 'operator' was not declared in this scope
Please expose me for the C++ noob that I am.
Here's a compilable/runnable version of your code (runnable at ideone here)
struct Visitor { };
struct Env { };
struct InappropriateFunction { };
class AbsTree {
public:
AbsTree();
virtual ~AbsTree() =0;
virtual void accept(Visitor &visitor) const = 0;
virtual void execute(Env &ctxt) const throw (InappropriateFunction);
};
class Operation: public AbsTree{
public:
Operation(char oper);
virtual ~Operation();
virtual void accept (Visitor &visitor) const;
char getOperator() const;
private:
char operator_;
};
AbsTree::AbsTree() {}
AbsTree::~AbsTree() {}
void AbsTree::accept(Visitor &visitor) const{}
void AbsTree::execute(Env &ctxt) const throw (InappropriateFunction) {}
Operation::Operation(char oper): operator_(oper) {}
Operation::~Operation(){}
void Operation::accept(Visitor &visitor) const{}
char Operation::getOperator() const {
return operator_;
}
int main()
{
Operation o('x');
Visitor my_visitor;
o.accept(my_visitor);
o.getOperator();
}
Basically, you've got to take more care to make sure the functions you define match your declarations - that includes const and throw specifications and return type. Further, operator is a reserved keyword and you can not use it to name your own variables.
Separately, exception specifications are deprecated... best to leave them out as they never proved useful. (C++11 has a noexcept keyword that's occasionally useful if you want to make it clear that a function can be used in code making exception guarantees - might get a little extra optimisation too, but if an exception is raised in/under the function your program will call std::terminate).
AbsTree is an abstract class, like you said. This means that you need to create a derived class in order to provider an implementation.
// ConcreteTree.h
#include "AbsTree.h"
class ConcreteTree : public AbsTree {
public:
ConcreteTree();
virtual ~ConcreteTree();
virtual void accept(Visitor &visitor) const;
virtual void execute(Env &ctxt) const throw (InappropriateFunction);
}
Then:
// ConcreteTree.cpp
#include "ConcreteTree.h"
ConcreteTree::ConcreteTree() {}
ConcreteTree::~ConcreteTree() {}
ConcreteTree::accept(Visitor &visitor) const{}
ConcreteTree::execute(Env &ctxt) const {}
I use MinGW latest version to compile the following code. I get the folowing message
y:/bbom/source/om0/basic/test.cpp: In static member function 'static void somecl
ass::init(class_object*)':
y:/bbom/source/om0/basic/test.cpp:68:50: error: no matching function for call to
'class_object::add_method(void (&)(object*, arch&))'
y:/bbom/source/om0/basic/test.cpp:68:50: note: candidate is:
y:/bbom/source/om0/basic/test.cpp:27:54: note: template<class p_function> void c
lass_object::add_method(typename p_function::funcion_type)
make.exe: *** [y:/bbom/bin/om0/basic/test.a] Error 1
Here is my code undressed from every thing not needed for this question
#include <exception>
class exception : public std::exception
{
public:
exception() {}
exception(const exception &);
~exception() throw() {}
virtual const char *what() const throw();
};
typedef unsigned id, version;
class class_object;
class object
{
public:
virtual ~object() {}
void *get_method(id);
class_object *get_class_object();
};
class class_object : public object
{
public:
template <class p_function>
void add_method(typename p_function::funcion_type p)
{add_method2((void *)p, p_function::function_id);}
void add_method2(void *, id);
};
template <typename p_func, id p_id>
class function
{
public:
typedef p_func function_type;
enum {function_id = p_id, };
function(object *p) {m_func = (p_func)p->get_method(p_id);}
p_func m_func;
};
class iface : public object
{
public:
iface(object *p) : m_object(p) {}
static void init(class_object *) {}
object *m_object;
};
class arch;
class archivable : public iface
{
public:
typedef void (*archive_func_type)(object *, arch &);
typedef function<archive_func_type, 0x5afeb287> archive_type;
archivable(object *);
archive_type archive;
};
class someclass : public object
{
public:
static void archive(object *, arch &)
{
}
static void init(class_object *p)
{
p->add_method<archivable::archive_type>(archive);
// the compiler says this call cannot be matched to
// add_method declared in class 'class_object'
}
};
What is wrong with my call to the template method in class_object::add_method<...>()
It appears you mistyped function_type as funcion_type on line 27 of test.cpp.
Typo. funcion_type should be function_type.
class ZooAnimal {
public:
virtual void draw();
int resolveType() {return myType;}
protected:
int myType;
};
class Bear : public ZooAnimal {
public:
Bear (const char *name) : myName(name), myType(1){}
void draw(){ };
private:
std::string myName;
};
void main()
{
}
When I am compiling above code I am geeting following error
error C2614: 'Bear' : illegal member initialization: 'myType' is not a base or member
Why am I getting the above error, as we can access protected member from the derived class?
You can't initialize base class member in derived class initializer lists.
You'll need to provide a constructor to the base class:
class ZooAnimal {
public:
ZooAnimal(int type) : myType(type) {}
virtual void draw();
int resolveType() {return myType;}
protected:
int myType;
};
and call it from the derived class:
class Bear : public ZooAnimal {
public:
//here//
Bear (const char *name) : ZooAnimal(1), myName(name) {}
void draw(){ };
private:
std::string myName;
};
consider the following class declarations:
namespace X {
template<class T>
class Foo {
public:
Foo();
virtual ~Foo();
T value() const;
};
template<class T>
class Foo<vector<T>> {
public:
Foo();
virtual ~Foo();
T value( const int ) const;
};
}
for them i have the following declaration in the foo.i file
%include "stl.i"
%include "std_string.i"
%include "std_vector.i"
namespace X {
using namespace std;
template<class T>
class Foo {
public:
Foo();
virtual ~Foo();
T value() const;
};
template<class T>
class Foo<vector<T> > {
public:
Foo();
virtual ~Foo();
T value( const int ) const;
};
%template(FooInt) Foo<int>;
%template(FooString) Foo<string>;
%template(FooVectorInt) Foo<vector<int> >;
}
the difference between the two classes is the specialisation of the later to vector container and the differrent signature of the value() method, where the first takes no arguments, while the second takes an expects an integer.
the wrapper code put together by swig wrapps the %template(FooVectorInt) wrong, in that it calls the value() method instead that of the specialised vector method value(const int). giving me the following compile error message:
foo_wrap.cxx: in function »int _wrap_FooVectorInt_value(lua_State*)«:
/home/noobsaibot/foo/bindings/src/lua/foo_wrap.cxx:6706:81: error: no matching function to call »X::Foo<std::vector<int> >::value() const«
/home/noobsaibot/foo/src/foo.h:78:5: note: candidate is: T X::Foo<std::vector<_RealType> >::value(int) const [with T = int, int = unsigned int]
any advices as to what i might be missing to make swig understand which function is the correct one?
cheers
You can achieve the result you want by doing:
%include "stl.i"
%include "std_string.i"
%include "std_vector.i"
namespace X {
using namespace std;
%rename(FooVectorInt) Foo<std::vector<int> >;
class Foo<std::vector<int> > {
public:
virtual ~Foo();
int value( const int ) const;
};
template<class T>
class Foo {
public:
Foo();
virtual ~Foo();
T value() const;
};
%template(FooInt) Foo<int>;
%template(FooString) Foo<string>;
}
This works because what you write in the interface file isn't C++ and all that matters is that the correct code is generated by SWIG. If you want to repeat this lots you can write macros (which is close to what %template is anyway).
Still this isn't a very clean solution - I expected this to "just work" with the specialisations and I can't see a simpler workaround either.