Given the abstract base class X, how to create another class of patterns D <T>, where T is the type of class originating from X?
I want to accept an object Message&that refers to either a class Message1or Message2. I want to be able to create MessageWithData<Message1>or MessageWithData<Message2>based on the base type of an object Message&. For example, see below:
class Message {};
class Message1 : public Message {};
class Message2 : public Message {};
template<typename Message1or2>
class MessageWithData : public Message1or2 { public: int x, y; }
class Handler()
{
public:
void process(const Message& message, int x, int y)
{
// create object messageWithData whose type is
// either a MessageWithData<Message1> or a MessageWithData<Message2>
// based on message type.. how do I do this?
//
messageWithData.dispatch(...)
}
};
messageWithData , Message, . , , , .
(, , http://jogear.net/dynamic-double-dispatch-and-templates)
+3
4
, (runtime-) . , .
, . message message, Message1, Message2. , . , .
. , CRTP:
template<class TDerived>
class Message{};
class Message1 : public Message<Message1>{};
class Message2 : public Message<Message2>{};
template<class TMessage>
class MessageWithData : public TMessage { public: int x, y; };
class Handler{
public:
template<class TMessage>
void process(Message<TMessage> const& m, int x, int y){
MessageWithData<TMessage> mwd;
mwd.x = 42;
mwd.y = 1337;
}
};
+3
Xeo, , , - . , RTTI, , , , process() , . .
- , , , , RTTI , :
#include <iostream>
#include <stdexcept>
struct Base
{
virtual ~Base() { }
template <class Op>
void for_rt_type(Op& op);
};
struct Derived1 : Base
{
void f() { std::cout << "Derived1::f()\n"; }
};
struct Derived2 : Base
{
void f() { std::cout << "Derived2::f()\n"; }
};
template <class Op>
void Base::for_rt_type(Op& op)
{
if (Derived1* p = dynamic_cast<Derived1*>(this))
op(p);
else if (Derived2* p = dynamic_cast<Derived2*>(this))
op(p);
else
throw std::runtime_error("unmatched dynamic type");
}
struct Op
{
template <typename T>
void operator()(T* p)
{
p->f();
}
};
int main()
{
Derived1 d1;
Derived2 d2;
Base* p1 = &d1;
Base* p2 = &d2;
Op op;
p1->for_rt_type(op);
p2->for_rt_type(op);
}
. factory : -}.
, for_rt_type : , "" , . , , API . , , , : (Op s), :
- , ..
- ,
- eg.
Derived1::value_typeisint,Derived2::value_typeisdouble- allows the algorithms for each to be efficient and use appropriate rounding, etc. Similarly for different types of containers, where only a common API is used.
- eg.
- You can use template metaprogramming, SFINAE, etc. to customize behavior along a specific path.
Personally, I believe that knowledge and the ability to apply this method (although rarely) is an important part of the assimilation of polymorphism.
+1