So I try:
class data_ppp {
public:
template <class T>
virtual boost::shared_ptr<T> getData()
{
return boost::shared_ptr<T>(new T());
}
};
class data_child : public data_ppp {
public:
template<>
getData<std::vector<int>>();
};
but cant get desired effect - I want to have in class data_child getData function that would only return boost::shared_ptr<std::vector<int>>. How to do such thing?
The only solution to your problem that I see now is:
class data_ppp
{
public:
template<class T>
std::shared_ptr<T> getData()
{ return std::shared_ptr<T>(new T()); }
};
class data_child : public data_ppp
{
public:
std::shared_ptr<int> getData()
{ return data_ppp::getData<int>(); }
};
Usage:
data_child dc;
dc.getData();
//dc.getData<float>(); // compilation error
According to your description. You want new function with different signature. Thus you will treat this getdata in the child class as if its very different function since the return type is different.
Member function templates (like your getData()) cannot be virtual. However, you can have a class template with virtual member functions:
template <class T>
class data_ppp {
public:
virtual boost::shared_ptr<T> getData()
{
return boost::shared_ptr<T>(new T());
}
};
THis allows quite a lot of customization.
1) you can define a class data_ppp< std::vector<int> >. If that class needs to behave as a generic T, then you are done.
2) If you want to override behavior for specific data uses but for all types T and you want to use the new functionality dynamically, you can derive from data_ppp<T>
template <class T>
class data_child: public data_ppp<T> {
public:
virtual boost::shared_ptr<T> getData()
{
// add logging, printing or whatever you want
return boost::shared_ptr<T>(new T());
}
};
3) If you only want to redefine getData() for T equal to std::vector<int>, you only have to specialize data_ppp
template <>
class data_ppp< std::vector<int> > {
typedef std::vector<int> T;
public:
virtual boost::shared_ptr< T > getData()
{
// add logging, printing or whatever you want
return boost::shared_ptr<T>(new T());
}
};
Related
I have an enum class Type. If I have a base class and a derived class like this:
template<Type T>
class Templated
{
public:
Type GetType() const
{
return T;
}
};
class DerivedTemplated : public Templated<Type::None>
{
};
Is this better in any way than having this:
class NoTemplate
{
public:
virtual Type GetType() const = 0;
};
class DerivedNoTemplate : public NoTemplate
{
public:
Type GetType() const override { return Type::None; }
};
Using templates is not necessary in this case, but I don't know if I should use them or not. I often store polymorphic collections of the base class, so in the templated case I would have to create an interface:
class ITemplated
{
public:
virtual Type GetType() const = 0;
};
and derive Templated from it. Are there any benefits to the templated one over the pure virtual function?
I think the first makes no sense. Because how would you use this? For example
template<Type T>
int int_of_type(const Templated<T> &bar) {
return hash(bar.get_type());
}
why not just write:
template<Type T>
int int_of_type(const Templated<T> &) {
return hash(T);
}
or
template<Type T>
int int_of_type<T>() {
return hash(T);
}
I see no way the get_type can be used where you couldn't just use T directly. Maybe you need a more complex example to show what you are trying to solve.
I am trying to solve a programming problem that consists of an object (call it Diagram), that contains several parameters. Each parameter (the Parameter class) can be one of several types: int, double, complex, string - to name a few.
So my first instinct was to define my Diagram class as having a vector of template parameters, which would look like this.
class Diagram
{
private:
std::vector<Parameter<T> > v;
};
This doesn't compile, and I understand why. So, based on the recommendations on this page How to declare data members that are objects of any type in a class, I modified my code to look like:
class ParameterBase
{
public:
virtual void setValue() = 0;
virtual ~ParameterBase() { }
};
template <typename T>
class Parameter : public ParameterBase
{
public:
void setValue() // I want this to be
// void setValue(const T & val)
{
// I want this to be
// value = val;
}
private:
T value;
};
class Diagram
{
public:
std::vector<ParameterBase *> v;
int type;
};
I'm having trouble figuring out how to call the setValue function with an appropriate templated parameter. It is not possible to have a templated parameter in the ParameterBase abstract base class. Any help is greatly appreciated.
P.S. I don't have the flexibility to use boost::any.
You got very close. I added a few bits because they're handy
class ParameterBase
{
public:
virtual ~ParameterBase() {}
template<class T> const T& get() const; //to be implimented after Parameter
template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};
template <typename T>
class Parameter : public ParameterBase
{
public:
Parameter(const T& rhs) :value(rhs) {}
const T& get() const {return value;}
void setValue(const T& rhs) {value=rhs;}
private:
T value;
};
//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }
class Diagram
{
public:
std::vector<ParameterBase*> v;
int type;
};
Diagram can then do stuff like these:
Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception
It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagram have the correct destructor, and make it non-copy-constructable, and non-copy-assignable.
The bellow implementation uses a few C++11 features but you will be
able to pick them apart.
#include <vector>
#include <memory>
class Parameter
{
private:
class ParameterBase {
public:
virtual ~ParameterBase() {}
virtual ParameterBase* copy() = 0;
virtual void foo() = 0;
};
template <typename T>
class ParameterModel : public ParameterBase {
public:
// take by value so we simply move twice, if movable
ParameterModel(const T& t) : t(t) {}
ParameterModel(T&& t) : t(t) {}
void foo() { t.foo(); }
ParameterModel* copy() { return new ParameterModel(*this); }
private:
T t;
};
public:
template <typename T>
Parameter(T&& t)
: pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}
// Movable and Copyable only
Parameter(Parameter&&) = default;
Parameter& operator=(Parameter&&) = default;
Parameter(const Parameter& other) : pp(other.pp->copy()) {};
Parameter operator=(const Parameter& other) {
pp.reset(other.pp->copy());
return *this;
};
// members
void foo() { pp->foo(); }
private:
std::unique_ptr<ParameterBase> pp;
};
class Diagram
{
public:
std::vector<Parameter> v;
int type;
};
struct X {
void foo() {}
};
struct Y {
void foo() {}
};
int main()
{
Diagram d;
d.v.emplace_back(X()); // int
// parameters are copyable and can be reassigned even with different
// impls
Parameter p = d.v.back();
Parameter other((Y()));
other = p;
return 0;
}
What does this code do? It hides the fact that we use inheritance to
implement parameters from our users. All they should need to know is
that we require a member function called foo. These requirements are
expressed in our ParameterBase. You need to identify these
requirements and add the to ParameterBase. This is basically a more
restrictive boost::any.
It is also quite close to what is described in Sean Parent's value semantics talk.
Let's say I have the following template class:
template<typename T>
class A
{
public:
// Lots of functions...
void someFunc(T obj)
{
// T must implement this function in order to be usable within class A.
obj.interfaceFunc();
}
};
This works fine, as the object I will use with the template class implements interfaceFunc().
However, if I pass a pointer to the template class then the compilation fails because the dereference syntax is incorrect. Because the template class contains a lot of other functions that I don't want to copy/paste into another partial specialisation if I can possibly help it, I have changed my class definition as follows:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
However, when virtualHelperFunction() is called, on an instance of B but when inside the someFunc() function of the parent A, it hits the assertion error.:
B<SomeObject> instance;
instance.someFunc(SomeObject()); // Assertion failure.
I've tried messing around with function pointers to solve this but I'm still fairly new to them, and the non-static pointer syntax confused me a bit. I'm assuming one could define a member pointer to the virtualHelperFunction() which is set to point to the base class version in A's constructor, but which is then overwritten in B's constructor to point to B's function. If so, would anyone be able to demonstrate the correct syntax to do this?
Thanks.
EDIT: If context is needed, the template class is an octree node which stores a hash table of type T. The interface function required is that the object can return a bounding box, in order for recursive insertion to function depending on whether the object's bounds intersect with the tree node's bounds.
https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.h
https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.tcc
This seems way too complicated. Why specialize the entire class if you just need one tiny bit specialized? All you need is a small utility that says "dereference this if it's a pointer, otherwise leave it alone". It could look like this:
template <typename T>
T& deref_if_pointer(T& t) { return t; }
template <typename T>
T& deref_if_pointer(T* t) { return *t; }
// ...
void someFunc(T obj) {
deref_if_pointer(obj).interfaceFunc();
}
You can easily extend deref_if_pointer to various smart pointers as well; just add another overload.
I'm not really sure what it is that you want to accomplish, so I'll have to guess. In what way does the following not satisfy your problem?
class A
{
public:
// Lots of functions...
void someFunc(T* obj)
{
// T must implement this function in order to be usable within class A.
obj->interfaceFunc();
}
void someFunc(T obj)
{
// T must implement this function in order to be usable within class A.
obj.interfaceFunc();
}
};
If you want to do it that way, then you need to take a reference instead of a pointer in the first partial specialization:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T& obj)
{
obj.interfaceFunc();
}
};
// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
Your code doesn't compile. template<typename T*> is illegal and you do not have any partial specializations as you claim.
This works:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Unspecialized template
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
// Partial specialisation
template<typename T>
class B<T*> : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T** obj)
{
(*obj)->interfaceFunc();
}
};
int main() {
B<SomeObject> instance1;
instance1.someFunc(SomeObject());
B<SomeObject*> instance2;
SomeObject x;
instance2.someFunc(&x);
}
I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print
template <typename T>
class BaseQueue
{
public :
virtual void push_back(T value) = 0;
//other virtual methods
};
template <typename T>
class BaseDeque: public virtual BaseQueue<T>
{
public:
virtual void push_front(T value) = 0;
//other virtual methods
};
//Realisation
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata;
public:
VectorQueue()
{
adata = array();
}
void push_back(T value)
{
adata.push_back(value);
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
VectorDeque<int> vd = VectorDeque<int>();//here is a error
int i;
std::cin >> i;
return 0;
}
I have such error: "C2259: 'VectorDeque' : cannot instantiate abstract class ...". How can I fix it? Class VectorQueue has realize every virtual method of BaseQueue class already. But the compiler doesn't know it. The only way I see is to write something like this:
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
void push_back(T value)
{
VectorQueue::push_back(value);
}
//repeat it fo every virtual method of BaseQueue class (interface)
};
But it's awful.
push_back from BaseQueue isn't implemented on the BaseDeque side of the inheritance chain, and thus the childmost class is still abstract.
I think you're trying to force a class relationship here that shouldn't exist. Note how in the standard library deque and vector are distinct container types and things like queue adapt those containers to very precise interfaces rather than trying to inherit.
Even if you solve your diamond issue (or follow #Mark B's advice and keep them separate), you have a few other issues in there:
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata; // if this is private, VectorDeque can't reach it
public:
// constructors have an initializer section
// member variables should be initialized there, not in the body
VectorQueue()
// : adata() // however, no need to explicitly call default constructor
{
// adata = array();
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>
{
void push_front(T value)
{
// if adata is protected, you can just access it. No need for scoping
/*VectorQueue::*/ adata.push_front(value);
// Error: std::vector doesn't have a method push_front.
// Perhaps you meant to use std::list?
}
};
Multiple inheritance and static polymorphism are of help, for instance:
// Abstract bases
template <typename T, typename Val>
class BaseQueue
{
public :
void push_back(Val val)
{
static_cast<T*>(this)->push_back(val);
}
// ...
};
template <typename T, typename Val>
class BaseDeque
{
public:
void push_front(Val val)
{
static_cast<T*>(this)->push_front(val);
}
// ...
};
// Concrete class
#include <deque>
template <typename Val>
class QueueDeque:
public BaseQueue<QueueDeque<Val>, Val>,
public BaseDeque<QueueDeque<Val>, Val>
{
std::deque<Val> vals;
public:
void push_front(Val val)
{
vals.push_front(val);
}
void push_back(Val val)
{
vals.push_back(val);
}
// etc..
};
int main()
{
QueueDeque<int> vd;// no more error
vd.push_front(5);
vd.push_back(0);
return 0;
}