This question was migrated from Software Engineering Stack Exchange because it can be answered on Stack Overflow.
Migrated 25 days ago.
I am writing a library using the Eigen Tensor library which makes use of templates. There is a base class called Layer from which many classes inherit from. Each child class must implement one of the virtual functions such as void Forward(const Tensor<2> &input) and void Backward(const Tensor<2> &gradient).
The thing is each child class accepts one specific input and gradient rank such as Tensor<2>, Tensor<3>, etc, so my base class ends up having
virtual void Forward(const Tensor<2> &input)
virtual void Forward(const Tensor<3> &input)
virtual void Forward(const Tensor<4> &input)
virtual void Backward(const Tensor<2> &gradient)
virtual void Backward(const Tensor<3> &gradient)
virtual void Backward(const Tensor<4> &gradient)
and it's not possible to template virtual functions. Is this poor design and is there a different design that can function similar to
template<int InputRank>
virtual void Forward(const Tensor<Rank> &input)
template<int OutputRank>
virtual void Backward(const Tensor<OutputRank> &gradient)
and allow me to place child objects into a single vector?
If any of the child classes don't implement all of those functions, then that shouldn't be where those functions are defined.
The child classes can inherit from a Layer that doesn't have those functions, and also from
template<size_t Rank>
struct CanBackpropagate {
virtual void Forward(const Tensor<Rank>& input) = 0;
virtual void Backward(const Tensor<Rank> gradient) = 0;
};
Or you have the base class BaseLayer, and
template<size_t Rank>
class Layer : public BaseLayer {
public:
virtual void Forward(const Tensor<Rank>& input) = 0;
virtual void Backward(const Tensor<Rank> gradient) = 0;
};
It's OK to have multiple containers for these, e.g. std::vector<Layer*> layers; alongside std::vector<CanBackpropagate<2> *> rank2; etc.
It's possible if you call the virtual function implementation from the base class to have something similar.
Here is how the base class would look like:
class Layer
{
public:
virtual void ForwardImpl(const void *tensor, size_t nrank) = 0;
template<size_t nrank>
void Forward(const std::array<float, nrank> &ntensor) {
ForwardImpl(&ntensor, nrank);
}
};
Above we extract the rank and call the virtual function with it.
Here is an example derived class:
class LayerImpl : public Layer {
public:
template<size_t n>
void Forward(const void *tensor)
{
const std::array<float, n> t = *static_cast<const std::array<float, n>*>(tensor);
//Implementation should be here
std::cout << n << std::endl;
}
void ForwardImpl(const void *tensor, size_t nrank) override {
ForwardTmpl<LayerImpl>(this, tensor, nrank);
}
};
And the glue:
template<class TyName>
inline void ForwardTmpl(TyName *pthis, const void *tensor, size_t nrank) {
const std::unordered_map<size_t, void (TyName::*)(const void*)> rank_map = {
{0, &TyName::template Forward<0>},
{1, &TyName::template Forward<1>},
{2, &TyName::template Forward<2>},
{3, &TyName::template Forward<3>},
};
// performs Forward for the specific nrank
(pthis->*rank_map.at(nrank))(tensor);
}
And example main:
int main() {
Layer *base = new LayerImpl{};
std::array<float, 2> testen;
base->Forward(testen);
}
Which in this case pints 2.
Here is also godbolt.
I think however this question is more suited for stack-overflow and not software engineering.
Related
I am trying to pass a CRTP type parameter to a virtual method. Consequently, the virtual method would need to be a template. However, this is not allowed by C++ (yet?), because it would mean that the size of the vtable -- the common way how compilers implement dynamic dispatch -- is unknown until all sources have been compiled and are being linked. (I found this reasoning during my search on SO.)
In my particular setting, however, there is a finite and known amount of CRTP specializations. Hence, it is possible to define a virtual method overload per specialization and override these in the subclasses. I have prepared a small MWE to demonstrate my situation. Consider the following CRTP hierarchy:
template<typename Actual>
struct CRTPBase
{
using actual_type = Actual;
void foo() { static_cast<actual_type*>(this)->foo(); }
int bar(int i) const { return static_cast<const actual_type*>(this)->bar(i); }
};
struct A : CRTPBase<A>
{
void foo() { /* do something A would do */ }
int bar(int i) const { return i + 1; }
};
struct B : CRTPBase<B>
{
void foo() { /* do something B would do */ }
int bar(int i) const { return i - 1; }
};
Next, I want to define a virtual class hierarchy with a virtual method to handle all specializations of CRTPBase<T>. Because I know the particular specializations, I can do as follows:
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(const CRTPBase<A> &o) override { /* much logic to handle A */ }
void accept_crtp(const CRTPBase<B> &o) override { /* similar logic to handle B */ }
};
Observe that there is one virtual method per specialization of CRTPBase<T>, both in the purely virtual base and in all its derived classes. This overhead easily blows out of proportion with increasing number of specializations of CRTPBase<T> and more derived classes of VirtualBase.
What I would like to do, is roughly the following:
struct VirtualBase
{
virtual ~VirtualBase() { }
template<typename T> virtual void accept_crtp(const CRTPBase<T> &o) = 0;
}
struct VirtualDerived : VirtualBase
{
template<typename T> void accept_crtp(const CRTPBase<T> &o) override {
/* one logic to handle any CRTPBase<T> */
}
};
For the reason mentioned in the beginning, this is not possible. User Mark Essel has faced the same issue in another SO post (in an answer, not a question, though).
The user proposes to declare and define the virtual methods for each specialization, but in the derived classes implement the actual logic in an additional template, non-virtual method and then forward calls from the virtual methods to that template method:
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(const CRTPBase<A> &o) override { accept_any_crtp(o); }
void accept_crtp(const CRTPBase<B> &o) override { accept_any_crtp(o); }
private:
template<typename T>
void accept_any_crtp(const CRTPBase<T> &o) {
/* one logic to handle any CRTPBase<T> */
}
};
While this approach avoids code duplication of the logic to handle the CRTPBase<T> specializations, it still requires explicitly writing one method per specialization in the virtual base and all derived classes.
My question is: How can the implementation overhead be reduced?
I have considered using an X macro of the form
#define CRTP_SPECIALIZATIONS_LIST(X) X(A) X(B) // lists all specializations, here A and B
to generate the methods in the virtual base and derived classes. The problem with that is, if the CRTP hierarchy is defined in CRTP.hpp and the virtual base and derived classes are declared/defined in other source files, then the macro is "being leaked" by the header to all translation units that include it. Is there a more elegant way to solve this? Is there maybe a template way of achieving the same goal, perhaps with a variadic template type?
Your help is appreciated. Kind regards,
Immanuel
As all types are known, you might use std::variant to have a free visitor implementation:
using MyVariant =
std::variant<std::reference_wrapper<const CRTPBase<A>>,
std::reference_wrapper<const CRTPBase<B>>,
// ...
>
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(MyVariant) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(MyVariant var) override
{
std::visit([/*this*/](const auto& crtp){ /*...*/ }, var);
}
};
If you write a CRTP base with the different accept_crtp() overloads that all delegate to a derived class' method, that derived class' method can be a template. That CRTP base can also be used to implement a virtual base:
// declare virtual interface
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
// implement virtual interface by delegating to derived class generic method
template<typename DerivedType>
struct CRTPDerived : VirtualBase
{
using derived_type = DerivedType;
virtual void accept_crtp(const CRTPBase<A> &o)
{ static_cast<derived_type*>(this)->accept_any_crtp(o); }
virtual void accept_crtp(const CRTPBase<B> &o)
{ static_cast<derived_type*>(this)->accept_any_crtp(o); }
};
// implement generic method
struct VirtualDerived : CRTPDerived<VirtualDerived>
{
private:
template<typename T>
void accept_any_crtp(const CRTPBase<T> &o) {
/* one logic to handle any CRTPBase<T> */
}
};
I have found a convenient solution to my problem. It scales well, meaning that the amount of code grows linearly with the number of virtual methods (rather than having number of virtual methods times number of CRTP classes). Further, my solution resolves the actual type of CRTPBase<T> at compile time; no dynamic dispatch except for the virtual method call. Thanks to Ulrich Eckhardt for pointing me in the right direction with his idea of using CRTP in the class hierarchy of VirtualBase.
I will describe how to solve this for a single method. This process can then be repeated for each method. The idea is to generate a purely virtual method in the VirtualBase for each concrete type of CRTPBase<T> and to generate implementations of these methods in all derived classes. The problem with generating methods at compile time is that templates do not allow us to generate method names. The trick here is to exploit overloading semantics and use a tag type to perform tag dispatching.
Let me explain along the example. Given the CRTP hierarchy (note that i slightly changed it for demonstrational purpose)
template<typename Actual>
struct CRTPBase
{
using actual_type = Actual;
actual_type & actual() { return *static_cast<actual_type*>(this); }
const actual_type & actual() const {
return *static_cast<const actual_type*>(this);
}
void foo() const { actual().foo(); }
int bar(int i) const { return actual().bar(i); }
void baz(float x, float y) { actual().baz(x, y); }
};
struct A : CRTPBase<A>
{
void foo() const { }
int bar(int i) const { return i + 'A'; }
void baz(float x, float y) { }
};
struct B : CRTPBase<B>
{
void foo() const { }
int bar(int i) const { return i + 'B'; }
void baz(float x, float y) { }
};
we want to declare a virtual method bark() in the class hierarchy VirtualBase, that accepts any subclass of CRTPBase<T> as parameter. We create a helper tag type bark_t to enable overload resolution.
struct VirtualBase
{
private:
virtual void operator()(bark_t, const A&) const = 0;
virtual void operator()(bark_t, const B&) const = 0;
public:
template<typename T>
void bark(const T &o) const { operator()(bark_t{}, o); }
};
The template method is generic and calls to the proper operator() thanks to overload resolution. The tag type is used here to select the correct implementation. (We want to support multiple methods, not just bark().)
Next we define an implementation of operator() in the derived classes using CRTP:
template<typename Actual>
struct VirtualCRTP : VirtualBase
{
using actual_type = Actual;
actual_type & actual() { return *static_cast<actual_type*>(this); }
const actual_type & actual() const {
return *static_cast<const actual_type*>(this);
}
void operator()(bark_t{}, const A &o) const override { actual()(bark_t{}, o); }
void operator()(bark_t{}, const B &o) const override { actual()(bark_t{}, o); }
};
Note that the implementation calls to some method operator() of static type Actual. We need to implement this next in the implementations of VirtualBase:
struct VirtualDerivedX : VirtualCRTP<VirtualDerivedX>
{
template<typename T>
void operator()(bark_t, const T &o) { /* generic implementation goes here */ }
};
struct VirtualDerivedY : VirtualCRTP<VirtualDerivedY>
{
template<typename T>
void operator()(bark_t, const T &o) { /* generic implementation goes here */ }
};
At this point you might wonder "What did we gain here?". So far, we need to write one method operator() per actual type of CRTPBase<T>. Only in VirtualBase and VirtualCRTP, but still more than we want to write. The neat thing is, we can now generate methods operator(), both the purely virtual declarations in VirtualBase and the implementation in VirtualCRTP. To do so, I have defined a generic helper class. I put the full code with this helper class and the example on Godbolt.
We can use this helper class to declare new virtual methods that take as first parameter an instance of a list of types, as well as additional parameters. It also takes care of const-ness of the parameters and the methods.
struct bark_t : const_virtual_crtp_helper<bark_t>::
crtp_args<const A&, const B&>::
args<> { };
struct quack_t : virtual_crtp_helper<quack_t>::
crtp_args<const A&, const B&>::
args<int, float> { };
struct roar_t : const_virtual_crtp_helper<roar_t>::
crtp_args<A&, B&>::
args<const std::vector<int>&> { };
/*----- Virtual Class Hierarchy taking CRTP parameter ------------------------*/
struct VirtualBase : bark_t::base_type
, quack_t::base_type
, roar_t::base_type
{
virtual ~VirtualBase() { }
/* Declare generic `bark()`. */
using bark_t::base_type::operator();
template<typename T>
void bark(const T &o) const { operator()(bark_t{}, o); }
/* Declare generic `quack()`. */
using quack_t::base_type::operator();
template<typename T>
void quack(const T &o, int i, float f) { operator()(quack_t{}, o, i, f); }
/* Declare generic `roar()`. */
using roar_t::base_type::operator();
template<typename T>
void roar(T &o, const std::vector<int> &v) const { operator()(roar_t{}, o, v); }
};
template<typename Actual>
struct VirtualCRTP : VirtualBase
, bark_t::derived_type<Actual>
, quack_t::derived_type<Actual>
, roar_t::derived_type<Actual>
{ };
struct VirtualDerivedX : VirtualCRTP<VirtualDerivedX>
{
private:
/* Implement generic `bark()`. */
friend const_virtual_crtp_helper<bark_t>;
template<typename T>
void operator()(bark_t, const T&) const { /* generic bark() goes here */ }
/* Implement generic `quack()`. */
friend virtual_crtp_helper<quack_t>;
template<typename T>
void operator()(quack_t, const T&, int, float) { /* generic quack() goes here */ }
/* Implement generic `roar()`. */
friend const_virtual_crtp_helper<roar_t>;
template<typename T>
void operator()(roar_t, T&, const std::vector<int>&) const { /* generic roar() goes here */ }
};
struct VirtualDerivedY : VirtualCRTP<VirtualDerivedY>
{
private:
/* Implement generic `bark()`. */
friend const_virtual_crtp_helper<bark_t>;
template<typename T>
void operator()(bark_t, const T&) const { /* generic bark() goes here */ }
/* Implement generic `quack()`. */
friend virtual_crtp_helper<quack_t>;
template<typename T>
void operator()(quack_t, const T&, int, float) { /* generic quack() goes here */ }
/* Implement generic `roar()`. */
friend const_virtual_crtp_helper<roar_t>;
template<typename T>
void operator()(roar_t, T&, const std::vector<int>&) const { /* generic roar() goes here */ }
};
In the example I declare three helper types for the three methods I want to implement. The base_type introduces the purely virtual methods to VirtualBase and the derived_type<Actual> imports the implementations of these methods. To do so, I use virtual inheritance to resolve the occuring dreaded diamond ;)
One downside is that one has to declare virtual_crtp_helper types as friend in the derived classes. Maybe someone knows how to avoid that?
To sum up: To add a method to the class hierarchy, one has to
Declare a helper type for the method using virtual_crtp_helper<T> or const_virtual_crtp_helper<T>.
Have VirtualBase inherit from this type's base_type and define the method as generic template.
Have VirtualCRTP<Actual> inherit from the helper type's derived_type<Actual>.
For each derived class, implement the actual logic in templated and tagged operator().
I am happy to hear your thoughts and am looking forward to improvements.
Immanuel
let's say I have the following classes:
class Base {
public:
virtual int do_something() = 0;
protected:
virtual int give_intermediate_result(int) = 0;
int m_some_shared_resources;
};
class Foo : public Base {
public:
virtual int do_something() override { return give_intermediate_result(1); }
protected:
virtual int give_intermediate_result(int a) override { return a*2; }
};
// and something like this:
class FooMixinA : public virtual Base {
protected:
virtual int give_intermediate_result(int) override;
};
class FooMixinB : public virtual Base {
public:
virtual int do_something() override;
};
What I would like to do is something like this:
Foo<FooMixinA, FooMixinB> myfoo (...);
which basically should override Foo's implementation of do_something with that of FooMixinB and give_intermediate_result with that of FooMixinA. Additionally I want mixins to be able to replace other mixins functionality, i. e. the order of the mixins is important as one mixin may use (f. e. the get_intermediate_result of) another mixin.
At the same time they should all have access to some shared underlying resource.
Can I do something like that and if so how would I approach it?
template<class Base, template<class>class...Mixins>
struct Foo:Base{};
template<class Base, template<class>class M0, template<class>class...Mixins>
struct Foo<Base, M0, Mixins...>:M0<Foo<Base, Mixins...>>{};
struct Base{
virtual int A()=0;
virtual int B()=0;
virtual ~Base()=default;
};
template<class Base>
struct MixinA:Base{
int A() final{ return 3; }
};
template<class Base>
struct MixinB:Base{
int B() override{ return -1; }
};
template<class Base>
struct MixinB2:Base{
int B() final{ return 0; }
};
using Bob=Foo<Base, MixinA, MixinB2, MixinB>;
std::unique_ptr<Base> pBase=std::make_unique<Bob>();
std::cout << pBase->A() << pBase->B() <<'\n';
Leftmost mixins override rightmost ones here.
For the other way around
template<class Base, template<class>class M0, template<class>class...Mixins>
struct Foo<Base, M0, Mixins...>:Foo<M0<Base>, Mixins...>{};
We can remove the Base argument of Foo if you really want. For right-to-left application:
template<template<class>class...Mixins>
struct Foo:Base{};
template<template<class>class M0, template<class>class...Mixins>
struct Foo<M0, Mixins...>:M0<Foo<Mixins...>>{};
it is easy. For left-to-right, you need to get fancier.
I'm having some trouble with C++: I have a class Primitive, it contains a member variable of an abstract buffer class..
Concrete buffer classes exist in many different forms for many different vertex types.. point-colour-normal, point-texcoord-normal, point-normal, point, etc.
I need to be able to add any type of vertex to a buffer held by classes that derive from primitive, for example quadsets, tri-lists, etc.
class Buffer {
//...
template<class T>
virtual void Add(const T&) = 0; // nope! Not compilable
virtual void Add(boost::any&) = 0; // I have been told no boost allowed either..
}
template<class T>
TypedBuffer : public Buffer {
//..
public:
std::vector<T> buffer;
public:
virtual void Add( const T& elem ) { buffer.push_back( elem ); }
}
class Primitive {
protected:
Buffer vertices;
public:
// How can I allow this to happen? \/
virtual void AddVert( const vec3& v) { vertices.Add( v ); }
}
class QuadSet : public Primitive { /*QuadSet Specifics..*/ }
void main(){
QuadSet q;
q.Add( COLOURED_VERT(vec3(1, 2, 3), vec3(0.5,0.5,0.5) ) );
}
Please Help!
When facing a similar problem, I ended up using type eraser. However in my example it requires to use something like reinterpret_cast:
class Buffer {
virtual void Add(const void*) = 0;
};
template <typename T>
class TypedBuffer: Buffer {
virtual void Add(const void* e) { buffer.push_back(*static_cast<T*>(e)); }
};
class Primitive {
virtual void AddVert(const vec3& v) { vertices.Add(reinterpret_cast<const void*>(&v)); }
};
Suppose I have the following classes:
class BaseObject {
public:
virtual int getSomeCommonProperty();
};
class Object1: public BaseObject {
public:
virtual int getSomeCommonProperty(); // optional
int getSomeSpecificProperty();
};
class BaseCollection {
public:
virtual void someCommonTask();
};
class Collection1: public BaseCollection {
public:
virtual void someCommonTask(); // optional
void someSpecificTask();
};
Each collection, derived from BaseCollection, deals with a specific object type (and only one type). But BaseCollection should be able to perform some tasks that are common to all objects, using only common object properties in BaseObject.
Currently, I have potentially three solutions in mind:
1) Store the objects list in BaseCollection, such as:
class BaseCollection {
vector<BaseObject*> objects;
};
The problem with this solution is that when I need to perform object-specific task in Collection1, I need a dynamic_cast<>, because I don't want to use virtual inherance for specific properties, applying to only one type of object. Considering that dynamic_cast<> could potentially get called millions of time per second, this seems an issue for a performance critical application.
2) Store the objects list in Collection1, such as:
class Collection1: public BaseCollection {
vector<Object1*> objects;
}
But then I need some way to access this object list in BaseCollection, to be able to perform some common tasks on them, ideally through an iterator. I would need to create a function that return a vector for the BaseCollection, but again, this does not seem very efficient, because the only way to do that is to create a new vector (potentially containing thousands of objects)...
3) Store the objects list in BaseCollection AND Collection1:
class BaseCollection {
public:
void someCommonTask(); // Use baseObjects
virtual void addObject() = 0;
protected:
vector<BaseObject*> baseObjects;
};
class Collection1: public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
}
Where the two lists actually contain the same objects. Is that as ugly as it sounds like?
I am looking for the right/correct/best design pattern for this type of problem and none of the 3 solutions exposed above really satisfies me...
Maybe it is possible to solve that problem with templates, but then I don't see a way to store a list of polymorphic collections like this:
vector<BaseCollection*> collections;
You can store all your objects of base and derived classes in one collection through the base class (smart) pointer. Using visitor design pattern and double dispatch mechanism you can call a function only on objects of a specific type without having to expose that function in the base class interface. For example:
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <stdio.h>
struct Visitor { // Visitor design patter
virtual void visit(struct BaseObject&) {}
virtual void visit(struct Object1&) {}
};
struct BaseObject {
unsigned ref_count_; // intrusive_ptr support
BaseObject() : ref_count_() {}
virtual ~BaseObject() {}
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
void intrusive_ptr_add_ref(BaseObject* p) { // intrusive_ptr support
++p->ref_count_;
}
void intrusive_ptr_release(BaseObject* p) { // intrusive_ptr support
if(!--p->ref_count_)
delete p;
}
struct Object1 : BaseObject {
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
void getSomeSpecificProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class T, class Functor>
struct FunctorVisitor : Visitor {
Functor f_;
FunctorVisitor(Functor f) : f_(f) {}
void visit(T& t) { f_(t); } // apply to T objects only
template<class P> void operator()(P const& p) { p->accept(*this); }
};
template<class T, class Functor>
FunctorVisitor<T, Functor> apply_to(Functor f)
{
return FunctorVisitor<T, Functor>(f);
}
int main()
{
typedef boost::intrusive_ptr<BaseObject> BaseObjectPtr;
typedef std::vector<BaseObjectPtr> Objects;
Objects objects;
objects.push_back(BaseObjectPtr(new BaseObject));
objects.push_back(BaseObjectPtr(new Object1));
for_each(
objects.begin()
, objects.end()
, boost::bind(&BaseObject::getSomeCommonProperty, _1)
);
for_each(
objects.begin()
, objects.end()
, apply_to<BaseObject>(boost::bind(&BaseObject::getSomeCommonProperty, _1))
);
for_each(
objects.begin()
, objects.end()
, apply_to<Object1>(boost::bind(&Object1::getSomeSpecificProperty, _1))
);
}
Output:
$ ./test
virtual void BaseObject::getSomeCommonProperty()
virtual void Object1::getSomeCommonProperty()
virtual void BaseObject::getSomeCommonProperty()
void Object1::getSomeSpecificProperty()
I think you should go for option 1 but use a static cast instead. After all the derived collection knows the type of the member variable for sure.
This answer explains it very well.
Id use nested adapter as in below example. You have to specialize it for every class you want to do a fancy update
!The example has memory leak - allocated A, B, Q objects are not deleted!
#include <iostream>
#include <vector>
#include <algorithm>
class Q
{
public:
virtual void Foo()
{
std::cout << "Q::Foo()" << std::endl;
}
};
class A
{
public:
virtual void Foo()
{
std::cout << "A::Foo()" << std::endl;
}
};
class B : public A
{
public:
virtual void Foo()
{
std::cout << "B::Foo()" << std::endl;
}
virtual void BFoo()
{
std::cout << "B::BFoo()" << std::endl;
}
};
template <typename ElementType>
class C
{
public:
template <typename T>
void add(T* ptr){m_Collection.push_back(std::unique_ptr<Adapter>(new ConcreteAdapter<T>(ptr)));}
void updateAll()
{
std::for_each(m_Collection.begin(), m_Collection.end(), [&](std::unique_ptr<Adapter> &adapter)->void{adapter->update();});
}
private:
class Adapter
{
public:
virtual ElementType* get() = 0;
virtual void update(){get()->Foo();}
};
template <typename T>
class ConcreteAdapter : public Adapter
{
public:
ConcreteAdapter(T* ptr) : m_Ptr(ptr){}
virtual T* get(){return m_Ptr;}
protected:
T* m_Ptr;
};
template <>
class ConcreteAdapter<B> : public Adapter
{
public:
ConcreteAdapter(B* ptr) : m_Ptr(ptr){}
virtual B* get(){return m_Ptr;}
virtual void update()
{
get()->Foo();
get()->BFoo();
}
private:
B* m_Ptr;
};
std::vector<std::unique_ptr<Adapter>> m_Collection;
};
int main()
{
C<A> c;
c.add(new A());
c.add(new B());
//c.add(new Q()); //error - correct
c.updateAll();
return 0;
}
Maybe this will do the trick here ?
class CollectionManipulator {
public:
void someCommonTask(BaseCollection& coll) {
for(unsigned int i = 0; i < coll.size(); i++)
someCommonTask(coll.getObj(i));
}
private:
void someCommonTask(BaseObject*); // Use baseObjects
};
class BaseCollection {
friend class CollectionManipulator;
private:
virtual BaseObject* getObj(unsigned int) = 0;
virtual unsigned int size() const = 0;
};
class Collection1 : public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
private:
BaseObject* getObj(unsigned int value) {
return object[value];
}
unsigned int size() const {
return objects.size();
}
}
If you want abstract your container in Collection1 (like using list instead using vector), to use it in Manipulator, create an abstract iterator...
I think the solution should be a mix of factory method pattern and template method pattern. Take a look at those to refine your design.
Edit: Here is a sample code. GenericProduct is the BaseObject, it provides two methods, one that is general (though it could be overridden), and a specific method which does nothing, it is not a pure virtual so this class can be instantiated. SpecificProduct is a subclass, which implements the specific method in some way.
Now, Factory class is an abstract class that defines an interface for creating specific products by specific factories, it defines a pure virtual method createProduct which creates the product. Two concrete factories are created GenericFactory and SpecificFactory which create specific products.
Finally, the Consumer abstract class (which corresponds to BaseCollection in your code), it defines a pure virtual method for creating a factory createFactory in order to force subclasses to create their own concrete factories (and hence, the correct products). The class also define a method fillArray (prototype pattern) to fill the array with products created by the factory.
#include <iostream>
#include <vector>
using namespace std;
class GenericProduct{
public:
virtual void getSomeCommonProperty()
{
cout<<"Common Property\n";
}
virtual void getSomeSpecificProperty()
{
cout<<"Generic Has Nothing Specific\n";
}
};
class SpecificProduct : public GenericProduct{
public:
virtual void getSomeSpecificProperty()
{
cout<<"Specific Product Has a Specific Property\n";
}
};
class Factory
{
public:
virtual GenericProduct* createProduct() = 0;
};
class GenericFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new GenericProduct();
}
};
class SpecificFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new SpecificProduct();
}
};
class Consumer
{
protected:
vector<GenericProduct*> gp;
Factory* factory;
protected:
virtual void createFactory() = 0;
public:
void fillArray()
{
createFactory();
for(int i=0; i<10; i++)
{
gp.push_back(factory->createProduct());
}
}
virtual void someCommonTask()
{
cout<<"Performaing a Common Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeCommonProperty();
}
}
virtual void someSpecificTask()
{
cout<<"Performaing a Specific Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeSpecificProperty();
}
}
};
class GenericConsumer : public Consumer
{
virtual void createFactory()
{
factory = new GenericFactory();
}
};
class SpecificConsumer : public Consumer
{
virtual void createFactory()
{
factory = new SpecificFactory();
}
};
int main()
{
Consumer* c = new GenericConsumer();
c->fillArray();
c->someCommonTask();
return 0;
}
In a typical implementation of the Visitor pattern, the class must account for all variations (descendants) of the base class. There are many instances where the same method content in the visitor is applied to the different methods. A templated virtual method would be ideal in this case, but for now, this is not allowed.
So, can templated methods be used to resolve virtual methods of the parent class?
Given (the foundation):
struct Visitor_Base; // Forward declaration.
struct Base
{
virtual accept_visitor(Visitor_Base& visitor) = 0;
};
// More forward declarations
struct Base_Int;
struct Base_Long;
struct Base_Short;
struct Base_UInt;
struct Base_ULong;
struct Base_UShort;
struct Visitor_Base
{
virtual void operator()(Base_Int& b) = 0;
virtual void operator()(Base_Long& b) = 0;
virtual void operator()(Base_Short& b) = 0;
virtual void operator()(Base_UInt& b) = 0;
virtual void operator()(Base_ULong& b) = 0;
virtual void operator()(Base_UShort& b) = 0;
};
struct Base_Int : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
struct Base_Long : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
struct Base_Short : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
struct Base_UInt : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
struct Base_ULong : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
struct Base_UShort : public Base
{
void accept_visitor(Visitor_Base& visitor)
{
visitor(*this);
}
};
Now that the foundation is laid, here is where the kicker comes in (templated methods):
struct Visitor_Cout : public Visitor_Base
{
template <class Receiver>
void operator() (Receiver& r)
{
std::cout << "Visitor_Cout method not implemented.\n";
}
};
Intentionally, Visitor_Cout does not contain the keyword virtual in the method declaration. All the other attributes of the method signatures match the parent declaration (or perhaps specification).
In the big picture, this design allows developers to implement common visitation functionality that differs only by the type of the target object (the object receiving the visit). The implementation above is my suggestion for alerts when the derived visitor implementation hasn't implement an optional method.
Is this legal by the C++ specification?
(I don't trust when some says that it works with compiler XXX. This is a question against the general language.)
oh, I see what you're after. Try something like this:
template < typename Impl >
struct Funky_Visitor_Base : Visitor_Base
{
// err...
virtual void operator()(Base_Int& b) { Impl::apply(b) }
virtual void operator()(Base_Long& b) { Impl::apply(b) }
virtual void operator()(Base_Short& b) { Impl::apply(b) }
virtual void operator()(Base_UInt& b) { Impl::apply(b) }
virtual void operator()(Base_ULong& b) { Impl::apply(b) }
// this actually needs to be like so:
virtual void operator()(Base_UShort& b)
{
static_cast<impl *const>(this)->apply(b)
}
};
struct weird_visitor : Funky_Visitor_Base<weird_visitor>
{
// Omit this if you want the compiler to throw a fit instead of runtime error.
template < typename T >
void apply(T & t)
{
std::cout << "not implemented.";
}
void apply(Base_UInt & b) { std::cout << "Look what I can do!"; }
};
That said, you should look into the acyclic visitor pattern. It has misunderstood visitors built into the framework so you don't have to implement functions for stuff you'll never call.
Funny thing is that I actually used something very similar to this to build an acyclic visitor for a list of types. I applied a metafunction that basically builds Funky_Visitor_Base and turns an operator (something with an apply() like I show) into a visitor for that complete list. The objects are reflective so the apply() itself is actually a metafunction that builds based on whatever type it's hitting. Pretty cool and weird actually.
In your derived visitor class, Visitor_Cout, the operator() template does not override the operator() in the Visitor_Base. Per the C++03 standard (14.5.2/4):
A specialization of a member function template does not override a virtual function from a base class. [Example:
class B {
virtual void f(int);
};
class D : public B {
template <class T> void f(T); // does not override B::f(int)
void f(int i) { f<>(i); } // overriding function that calls
// the template instantiation
};
—end example]