I am trying to implement Heterogenous container, using pointers to non-template base class. While the derived class is a template.
Note: Derived class types are known at compile time.
Note: the container size is fixed.
First attempt: is using a helper array to hold integer representation of the correct type. Its size equal to the container size. Yet I ended up with many if statements.
my problem is slightly similar to this thread yet I don't know to how to use std::type_index.
I am trying to avoid solving this using Boost::variant and run-time polymorphism.
My question: is there better way to handle casting from the base class to the derived class ?
Edit1 in my actual problem. the template class has 16 different types.
example:
template<typename Color, typename Smell, typename Shape, typename Origin>
class Fruit{};
Implementation:
class Plant
{ public: std::string sound = "I am jst a plant";};
template <typename T>
class Fruit : public Plant
{public: std::string sound = "I am jst a Fruit!";};
// list of types known at compile time.
struct Apple{ }; // types = 0
struct Orange{ }; // types = 1
struct Banana{ }; // types = 2
template <>
class Fruit<Apple> : public Plant
{public: std::string sound = "I am Apple";};
template <>
class Fruit<Orange> : public Plant
{public: std::string sound = "I am Orange";};
template <>
class Fruit<Banana> : public Plant
{public: std::string sound = "I am Banana";};
template <typename T>
void MakeSound(T fruit)
{
std::cout << fruit->sound << std::endl;
}
int main() {
Plant* Basket[5] = {nullptr};
int types[5] = {0};
Basket[0] = new Fruit<Apple>;
types[0] = 0;
Basket[1] = new Fruit<Orange>;
types[1] = 1;
Basket[2] = new Fruit<Orange>;
types[2] = 1;
Basket[3] = new Fruit<Apple>;
types[3] = 0;
Basket[4] = new Fruit<Apple>;
types[4] = 0;
for (int i = 0; i < 5; ++i)
{
if (types[i] == 0)
{
MakeSound(static_cast<Fruit<Apple> *>(Basket[i]));
}
else if (types[i] == 1)
{
MakeSound(static_cast<Fruit<Orange> *>(Basket[i]));
}
else
{
MakeSound(static_cast<Fruit<Banana> *>(Basket[i]));
}
}
}
I suggest the use of a virtual function to detect id of the type of the derived object; id of the type that I suggest registered in the template class parameter (as the sound) to avoid the need of specializations fo Fruits.
And please: you tagged C++11; so use smart pointers.
An example of what I mean
#include <string>
#include <vector>
#include <memory>
#include <iostream>
struct Plant
{ virtual std::size_t getTypeId () = 0; };
struct Apple
{
static constexpr size_t typeId { 0U };
static std::string const & getSnd ()
{ static std::string sound { "I am Apple" }; return sound; }
};
struct Orange
{
static constexpr size_t typeId { 1U };
static std::string const & getSnd ()
{ static std::string sound { "I am Orange" }; return sound; }
};
struct Banana
{
static constexpr size_t typeId { 2U };
static std::string const & getSnd ()
{ static std::string sound { "I am Banana" }; return sound; }
};
template <typename T>
struct Fruit : public Plant
{
virtual std::size_t getTypeId () override { return T::typeId; }
static std::string const & getSnd () { return T::getSnd(); }
};
template <typename T>
void MakeSound(T fruit)
{ std::cout << fruit->getSnd() << std::endl; }
int main()
{
std::vector<std::unique_ptr<Plant>> bask;
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Banana>);
for ( auto const & up : bask)
{
switch ( up->getTypeId() )
{
case 0U:
MakeSound(static_cast<Fruit<Apple> *>(up.get()));
break;
case 1U:
MakeSound(static_cast<Fruit<Orange> *>(up.get()));
break;
case 2U:
MakeSound(static_cast<Fruit<Banana> *>(up.get()));
break;
default:
break;
}
}
}
Related
I am looking for some way to mark the class I want to cast to. I am quite new here on the site so please feel free to improve tags or other things.
For example, if I have:
template<class C>
class Rotateable
{
virtual void C Rotate() = 0;
};
class Circle : public Rotateable<Circle>
{
Circle Rotate() { /*impl here*/ }
};
class Square : public Rotateable<Square>
{
Square Rotate() { /*impl here*/ }
};
If I have a list or array of Rotateables, how can I store somewhere (in Rotateable?) the information of what class to try and cast to, in a way that I can access at runtime?
You can't have a virtual whose return type changes. But you can have type identifiers on polymorphic classes that tell you which class to cast to before calling the function. Take a look at something like this as the basic idea. (This is c++14 code. Feel free to strip out any parts that don't work for you if you aren't using c++14 features.)
#include <iostream>
#include <memory>
#include <vector>
size_t generate_id()
{
static size_t id = 0;
return id++;
}
template <typename T>
size_t type_id()
{
static size_t id = generate_id();
return id;
}
class BaseRotatable
{
public:
template <typename T>
bool is()
{
return type_id<T>() == type();
}
virtual size_t type() = 0;
};
template <typename T>
class Rotatable : public BaseRotatable
{
public:
size_t type() override
{
return type_id<T>();
}
};
class Circle : public Rotatable<Circle>
{
public:
Circle Rotate()
{
return *this; // Make this do something fancier.
}
};
class Square : public Rotatable<Square>
{
public:
Square Rotate()
{
return *this; // Make this do something fancier.
}
};
template <typename T, typename... Args>
std::unique_ptr<BaseRotatable> factory(Args... args)
{
T* ptr = new T(args...);
return std::unique_ptr<BaseRotatable>{dynamic_cast<BaseRotatable*>(ptr)};
}
int main() {
// Build a vector of rotatables.
std::vector<std::unique_ptr<BaseRotatable>> rotatables;
rotatables.emplace_back(factory<Circle>());
rotatables.emplace_back(factory<Square>());
for (auto& rotatable : rotatables)
{
// You can also use a switch here.
if (rotatable->is<Circle>())
{
Circle& circle = *dynamic_cast<Circle*>(rotatable.get());
auto new_circle = circle.Rotate();
std::cout << "Type id: " << new_circle.type() << std::endl;
}
else if (rotatable->is<Square>())
{
Square& square = *dynamic_cast<Square*>(rotatable.get());
auto new_square = square.Rotate();
std::cout << "Type id: " << new_square.type() << std::endl;
}
}
return 0;
}
I need to assign unique integer value to each descendant of class Base that should be accessible by using pointer to those classes or its typenames.
I implemented it such way
class Base {
public:
int idCompType = InvalidCompType;
virtual int getCompType() = 0;
}
then in each descendant of base I should declare idCompType (for templates) and override getCompType (for pointers):
class Real1: public Base {
public:
int idCompType = 1;
int getCompType() override { return idCompType; }
}
now I can find comp type from pointer to base
Base *comp = getComp(...);
std::cout << comp->getCompType();
or using typename in template:
template <typename T>
int getType() {
return T::idCompType;
}
Is there a way to make it even simpler without double declaration idCompType and getCompType() in each descendant class? In Object Pascal I achieved this using virtual static methods, but their are not allowed in C++..
PS: the question is not about virtual static methods - virtual static method is just the one of the possible solutions and the way my problem was solved in other language.
My recommendation:
Changes to Base:
class Base {
public:
virtual int getCompType() = 0;
protected:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
Changes to the derived class:
class Real1: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
Here's a working program:
#include <iostream>
class Base {
public:
virtual int getCompType() = 0;
protected:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
class Real1: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
class Real2: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
template <typename T> int getCompType()
{
return T::getCompTypeImpl();
}
int main()
{
Real1 v1;
Real2 v2;
std::cout << v1.getCompType() << std::endl;
std::cout << v2.getCompType() << std::endl;
std::cout << getCompType<Real1>() << std::endl;
std::cout << getCompType<Real2>() << std::endl;
};
Output:
1
2
1
2
Here is a slight variant of #Sahu's version.
Instead of implementing the same getCompTypeImpl() in every derived class, put it in Base class.
template<typename T>
static int getCompTypeImpl()
{
return getNextCompType<T>();
}
Modify getNextCompType() to
template<typename T>
static int getNextCompType()
{
auto iter = m_table.find(std::type_index(typeid(T)));
if (iter != m_table.end())
{
return iter->second;
}
else
{
m_table.insert(std::make_pair(std::type_index(typeid(T)), ++nextType));
return nextType;
}
}
And finally introduce 2 new static data members.
private:
static std::map<std::type_index, int> m_table;
static int nextType;
Please find the full code here.
Admittedly this introduces 2 new static members and does a bit more work
than the original version from Sahu. But, this removes the burden of implementing the methods in
all the derived classes.
Yet another variation of #R Sahu's answer to eliminate duplication of code in the derived classes:
#include <iostream>
class Base {
public:
virtual int getCompType() const = 0;
template <typename T>
static int getCompTypeOf()
{
static int compType = getNextCompType();
return compType;
}
private:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
template <typename Derived, typename DeriveFrom = Base>
class TypeAssigner : DeriveFrom {
public:
int getCompType() const override
{
return Base::getCompTypeOf<Derived>();
}
};
class Real1: public TypeAssigner<Real1> {};
class Real2: public TypeAssigner<Real2> {};
class Real3 : public TypeAssigner<Real3, Real2> {};
int main()
{
Real1 v1;
Real2 v2;
Real3 v3;
std::cout << v1.getCompType() << '\n';
std::cout << v2.getCompType() << '\n';
std::cout << v3.getCompType() << '\n';
std::cout << Base::getCompTypeOf<Real1>() << '\n';
std::cout << Base::getCompTypeOf<Real2>() << '\n';
std::cout << Base::getCompTypeOf<Real3>() << '\n';
};
For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}
I have a class Foo which uses CRTP to inherit a template method from a parent class and avoid having to provide literally dozens of individual member methods. Something like this:
class Foo : public SomeBarClass<Foo>
{
//..
//from SomeBarClass
public:
template <class T> void onMsg(T* msg);
private:
IFoxMod* foxMod_;
};
Now, in the implementation for onMsg, I would like something like this:
template <class T>
void Foo::onMsg(T* msg)
{
if (foxMod_->shouldDoStuff(msg))
{
//do stuff
}
}
and there can be many foxMod_ types (one of them instantiated in the Foo constructor by name given in config file) as long as they abide by the common interface of providing a bool shouldDoStuff method. The problem, is that this leads me to define the following:
struct IFoxMod
{
virtual ~IFoxMod() {}
template <class T> shouldDoStuff(T* msg) = 0;
};
for all of the FoxMods to implement (like, class redMountainLogic : public IFoxMod might have it's own way of discerning, when it is appropiate to do stuff).
This is illegal though because one cannot have virtual templates and I'm trying to find a workaround for it. Basically, I need to have dynamic dispatch, but the argument I am passing is a template. I can't think of a workaround.
Virtual function tables don't seem to get along well with template specializations. Not too surprising. VFTs are generally based on declaration order, which doesn't really exist with templates. One solution is to manually recreate VFTs.
Here's an example. It could probably be a little cleaner, but it works.
#include<iostream>
using namespace std;
// Message.h
template<int n>
struct MessageByInt {
typedef int Msg;
};
struct MessageOfHope {
int a;
int b;
static const int id = 0;
};
template<> struct MessageByInt<MessageOfHope::id> { typedef MessageOfHope Msg; };
struct MessageOfDoom {
int b;
int c;
static const int id = 1;
};
template<> struct MessageByInt<MessageOfDoom::id> { typedef MessageOfDoom Msg; };
const int nMessages = 2;
// IFoxMod.h
typedef bool(*callback)(void*);
struct IFoxMod {
callback vtable[nMessages];
template<typename MSG>
bool ShouldDoWork(MSG* msg) {
return vtable[MSG::id](msg);
}
};
template<typename TESTER, int n>
struct filler {
typedef typename MessageByInt<n>::Msg MSG;
typedef typename TESTER::template Tester<MSG> Tester;
static void fill(IFoxMod* impl) {
impl->vtable[n] = reinterpret_cast<callback>(&Tester::ReallyShouldDoWork);
filler<TESTER,n-1>::fill(impl);
}
};
template<typename TESTER>
struct filler<TESTER,-1>{
static void fill(IFoxMod* impl) {
}
};
// RedFox.h
struct RedFoxTester {
template<typename MSG>
struct Tester { // This struct exists to allow partial specialization
static bool ReallyShouldDoWork(MSG* msg) {
return msg->b == 2;
}
};
};
struct RedFoxMod : public IFoxMod {
RedFoxMod() {
filler<RedFoxTester,nMessages-1>::fill(this);
}
};
//Main
main() {
IFoxMod* fm = new RedFoxMod();
MessageOfHope mohb2 = {1, 2};
MessageOfDoom modb2 = {2, 3};
MessageOfHope mohbn2 = {2, 3};
MessageOfDoom modbn2 = {1, 2};
cout << fm->ShouldDoWork(&mohb2) << ", " << fm->ShouldDoWork(&modb2) << endl;
cout << fm->ShouldDoWork(&mohbn2) << ", " << fm->ShouldDoWork(&modbn2) << endl;
}
I don't know if it is possible, I checked on StackOverflow, I found a lot of stuff but nothing that really fit my problem (or I don't see the relation).
What I'd like to do is something like that:
class Bean
{
public:
Bean(){}
virtual ~Bean(){}
template <class T>
bool set_(T){return false;}
template <class T>
bool get_(T&){return false;}
};
template <class T>
class GenericBean: public Bean
{
protected:
T type;
};
class Prova : public GenericBean<int>
{
public:
Prova(){type = 0;}
template<int> bool set_(int value){ type=value;}
template<int> bool get_(int& value){value = type;}
};
I'd like to have on object like Prova, cast to Bean and get the specialized function,
What I want to do is something like this:
#include <vector>
#include "Bean.h"
using namespace std;
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class ReturnValue, class Item>
bool Get(ReturnValue & val)
{
for(size_t i = 0; i < m_vData.size(); i++)
{
if(m_vData[i].get_<ReturnValue>(val))
return true;
}
}
template <class Item, class Value>
bool Set(Value val)
{
Item bean;
if(bean.set_<Value>(val))
{
m_vData.push_back(bean);
return true;
}
return false;
}
protected:
vector<Bean> m_vData;
};
Main:
#include "VirtualMessage.h"
#include "Bean.h"
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed");
}
this code doesn't compile
Maybe nobody will use it, but I wrote something that fits my need. It's not perfect, I have to work on it but is a begin:
#define UNIQUE(T) unsigned int GetID(){return UniqueType<T>::id();}
struct UniqueTypeBase
{
static unsigned int _ids;
};
unsigned int UniqueTypeBase::_ids = 0;
template <class T>
struct UniqueType : public UniqueTypeBase
{
static const unsigned int id()
{
static unsigned int typeId = 0;
if (typeId == 0)
typeId = ++_ids;
return typeId;
}
};
template <class T>
class TemplateBean
{
public:
T m_tValue;
template<class T> set_(T){return false;}
template<class T> get_(T&){return false;}
bool set_(T value){ m_tValue = value; return true;}
bool get_(T& value) { value = m_tValue;return true;}
};
class Prova : public TemplateBean<int>
{
public:
UNIQUE(Prova)
Prova(){m_tValue = 0;}
};
class Prova2 : public TemplateBean<float>
{
public:
UNIQUE(Prova2)
Prova2(){m_tValue = 0;}
};
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class Item, class ReturnValue>
bool Get(ReturnValue & val)
{
Item a;
map<unsigned int, void*>::iterator it;
it = m_TagMap.find(a.GetID());
if(it != m_TagMap.end())
{
Item* pItem = reinterpret_cast<Item*>(it->second);
if(pItem->get_(val))
return true;
}
return false;
}
template <class Item, class Value>
bool Set(Value val)
{
Item* pBean = new Item();
if(pBean->set_(val))
{
m_TagMap[pBean->GetID()] = (void*)pBean;
return true;
}
return false;
}
protected:
map<unsigned int, void*> m_TagMap;
};
Test Main:
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed\n");
if(!msg.Set<Prova,float>(4.00))
printf("Test 2 succed\n");
if(msg.Set<Prova2,float>(4.00))
printf("Test 3 succed\n");
int a=0;
if(msg.Get<Prova>(a))
printf("%d = 4...if 4=4 test passed\n",a);
float b=0;
if(msg.Get<Prova2>(b))
printf("%f = 4...if 4=4 test passed\n",b);
getchar();
}
I think you misunderstood the use of templates.
Templates are blueprints to build classes or methods, that the compiler use to produce real classes and methods (which is called instantiation).
As such, they are purely a compile-time facility. Therefore, they cannot be virtual, and thus overloading a template method in a derived class does not mean what you expect. It hides the base class method when used from derived (statically) but you still call the base class method if you use a reference or pointer to the base class.
What you are trying to achieve is, unfortunately, impossible with templates: it requires a runtime check.
Furthermore, you are using a std::vector<Bean> which will not work as intended. Polymorphic types shall not be manipulated by values in C++, you need a std::vector< std::unique_ptr<Bean> > or boost::ptr_vector<Bean>...
I would recommend reading a good C++ primer before attempting the kind of task you have set yourself upon. You need a basic introduction to C++ paradigms... and gotchas. And there are a lot of gotchas.