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.
Related
I'm trying to find a way to make a function that is a friend to a given class. That function is another class' method and is a specialization of a template. Without specialization, I have the following compiling code in Visual Studio:
ClassA.h:
#pragma once
#include "classB.h"
class A
{
private:
int data;
void Operate();
public:
A();
~A();
template<class T> friend void B::DoSomething(const T& arg);
};
ClassB.h:
#pragma once
class B
{
private:
int data;
template<typename T> void DoSomething(const T& arg)
{
T copy = arg;
copy.Operate();
data = 3;
};
/*
template<> void DoSomething(const A& arg)
{
A copy = arg;
copy.Operate();
data = 4;
};
*/
public:
B();
~B();
};
ClassA.cpp:
#include "classA.h"
A::A()
{
data = 1;
}
A::~A()
{
}
void A::Operate()
{
data = 2;
}
ClassB.cpp:
#include "classB.h"
B::B()
{
data = 1;
}
B::~B()
{
}
How do I specialize the template and make it a friend instead of the entire template? If that is possible, where do I place it then? Do I need forward declarations anywhere? Which headers would I need to include, etc.?
I tried to uncomment the block in classB.h and add #include "classA.h" on top of it. I also tried to replace the line template<class T> friend void B::DoSomething(const T& arg); in classA.h with something like template<> friend void B::DoSomething(const A& arg);. Nothing helped. It refuses to compile.
I would appreciate any insight!
To make B::DoSomething<int> a friend of A, use
friend void B::template DoSomething<int>(const int& arg);
To make B::DoSomething<A> a friend of A, use
friend void B::template DoSomething<A>(const A& arg);
Please note that in order to be able to do that, DoSomething has to be a public member of B.
Further reading: Where and why do I have to put the "template" and "typename" keywords?
#include <iostream>
using namespace std;
class c1{
public:
void f(){std::cout<<"In f1\n";}
};
class c2{
public:
void f(){std::cout<<"In f2\n";}
};
template <typename T>
class c:public c1, c2 {
T* pT;
public:
T* operator->() { return pT; }
};
int main()
{
c<c1>* cMain;
cMain->f();
return 0;
}
Error:
g++ cache.cc
cache.cc: In function ‘int main()’:
cache.cc:22:8: error: request for member ‘f’ is ambiguous
cMain->f();
^
cache.cc:9:8: note: candidates are: void c2::f()
void f(){std::cout<<"In f2\n";}
^
cache.cc:5:8: note: void c1::f()
void f(){std::cout<<"In f1\n";}
why is it not accessing the function f of c1 as specified in the template? is my template usage wrong? How can i make it point to the required class using template.?
The problem is that you're using pointers. You aren't calling c::operator-> but just dereferencing cMain which is uninitialized and leads to UB. Removing the pointers (for the most part) fixes the problem:
#include <iostream>
class c1{
public:
void f(){std::cout<<"In f1\n";}
};
class c2{
public:
void f(){std::cout<<"In f2\n";}
};
template <typename T>
class c { // No longer derives from c1 and c2
T t; // No longer a pointer
public:
T* operator->() { return &t; }
};
int main()
{
c<c1> cMain; // No longer a pointer
cMain->f(); // Calls c::operator->() now
return 0;
}
see it work
Of course you don't need c to derive from c1 and c2 (or anything) for this to work.
If you don't particularly need the pointer semantics for something else, you can add a function to c that redirects to the proper base class function:
template <typename T>
class c:public c1, c2 {
public:
void f() { T::f(); }
};
Your calling code is equivalent to
c<c1>* cMain;
(*cMain).f(); // equivalent to: c<c1> cMain; cMain.f();
Value *cMain has type of c<c1>. Obviously, now a call to f() is ambiguous, because both c1 and c2 has f() function and c<c1> inherits them both. Templates are not to blame (you can make class c non-template and get the same result).
If you want to call -> operator you should say (*cMain)->f(); but don't forget to initialize the pointer before.
I followed this example on how to override a template class in C++ with a specific template, but the Visual Studio compiler keeps complaining about some sort of syntax error. This is my code:
enum LFOType {
LIFO,
FIFO
};
template<typename DataType, LFOType Behavior, int MaxElems = 10>
class LFO {
public:
virtual DataType& top();
}
#include <string>
#include "LFO.h"
template<int MaxElems = 10>
class StringFIFO : public LFO<std::string, FIFO, MaxElems> {
public:
virtual ~StringFIFO() {};
};
Now I'm trying to override the function top() in the StringFIFO-class, but I cannot get it to work. So this is what I tried:
template<int MaxElems = 10>
class StringFIFO : public LFO<std::string, FIFO, MaxElems> {
public:
virtual ~StringFIFO() {};
std::string top() override;
};
Or instead of first overriding the declaration, just overriding it directly in the cpp-file:
template<int MaxElems>
std::string StringFIFO<MaxElems>::top<std::string, FIFO, MaxElems>() {
}
But none of these methods work. The compiler complains that 'std::basic_string<char>' is not identical or covariant to return type 'DataType&' of overridden function LFO<DataType, Behavior, MaxElems>::top.
What did I do wrong?
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")
I suspect I can't do this directly using a PIMPL pattern. Is it possible to have a smart pointer to a template class? I have not been able to compile by turning knobs on the shared_ptr declaration.
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Under Visual Studio 2008: "error C2065: 'T' : undeclared identifier". I receive a similar error under GCC. If I un-parameterize FooImpl (so that FooTempl inherits from FooImpl), the code will compile.
I suspect I can't paramaterize the smart pointer, but I could be wrong.
EDIT: The second Visual Studio error is more telling: "error C3203: 'FooImpl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type"
Jeff
I'm not entirely certain what you are trying to accomplish, but does this help?
Try 1:
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
template<class C>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<C> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Try 2:
// ============Foo.h ============
// Forward declare the implementation
class FooImplBase;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImplBase > m_impl;
};
// ============FooImpl.h ============
class FooImplBase {
public:
virtual void AnAPI();
virtual int AnotherAPI();
};
template <typename T>
class FooImpl : public FooImplBase
{
...
};
The code you have posted cannot compile since T does not mean anything in the context of Foo. The compiler expects a type called T here which does not exist there... Not entirely sure what you are trying to accomplish, but wouldn't the following solve your problem?
// ============Foo.h ============
class FooImplBase {
virtual void WhateverFooImplIsSupposedToDo() = 0;
};
template <typename T> class FooImpl : public FooImplBase {
T mInstance;
public:
FooImpl(T const & pInstance) : mInstance(pInstance) {}
virtual void WhateverFooImplIsSupposedToDo()
{
// implementation which deals with instances of T
}
};
class Foo
{
public:
Foo getInstance(const string& fooType) {
// use m_impl->WhateverFooImplIsSupposedToDo...
}
template < class T >
Foo( T const & pInstance ) : m_impl(new FooImpl<T>(pInstance)) {}
private:
shared_ptr< FooImplBase > m_impl;
};
You're doing it right, just make sure T is defined. This compiles for me on MSVC++ 2010:
#include <memory>
using namespace std;
template<class T>
class Blah {
public:
Blah() { }
};
class Foo {
public:
shared_ptr<Blah<int>> ptr;
Foo() : ptr(new Blah<int>()) { }
};
If you're on an older compiler that hasn't incorporated this feature of C++11 yet, change
shared_ptr<Blah<int>> ptr;
To
shared_ptr<Blah<int> > ptr;
So the compiler doesn't think the >> is a right shift. C++11 doesn't have this problem though.
I don't know in advance I am going to have a Blah, only a Blah.
From the language point of view, Blah<T> is meaningless because T doesn't exist. Depending on what you're exactly trying to do, you can
make Foo a template, too, so that you can declare a template parameter T:
template<typename T>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
which 'fixes' the choice of T when you declare a variable of type Foo<T>;
or make FooImpl explicitly derive from a common base:
class FooBase {
// need to define the interface here
};
// this is a class definition whereas previously you only needed a declaration
template<typename T>
class FooImpl: public FooBase {
// definition here
};
class Foo
{
public:
Foo getInstance(const string& fooType);
// we needed the definition of FooImpl for this member
// in addition this member is quite obviously a template
template<typename T>
void
set(FooImpl<T> const& foo)
{
m_impl.reset(new FooImpl<T>(foo));
}
// not a member template!
void
use()
{
// any use of m_impl will be through the FooBase interface
}
private:
shared_ptr<FooBase> m_impl;
};
where for a given Foo instance any kind of FooImpl<T> can be set dynamically and then used through the FooBase interface. This is a kind of type erasure as it's called in the C++ world.
We can use templates to write a generic smart pointer class. Following C++ code demonstrates the same. We don't need to call delete 'ptr', when the object 'ptr' goes out of scope, destructor for it is automatically.
#include<iostream>
using namespace std;
// A generic smart pointer class
template <class T>
class SmartPtr
{
T *ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T *p = NULL) { ptr = p; }
// Destructor
~SmartPtr() {
cout <<"Destructor called" << endl;
delete(ptr);
}
// Overloading dereferncing operator
T & operator * () { return *ptr; }
// Overloding arrow operator so that members of T can be accessed
// like a pointer (useful if T represents a class or struct or
// union type)
T * operator -> () { return ptr; }
};
int main()
{
SmartPtr<int> ptr(new int()); // Here we can create any data type pointer just like 'int'
*ptr = 20;
cout << *ptr;
return 0;
}
out put:
20
Destructor called