I have an application which will be receiving messages from another application. These messages will be XML fomatted strings, and they will contain a <messageType> tag. The message type will identify this message as a type of internal message. The following code shows my internal message structures.
namespace
Application1{
enum ApplicationAttributes{
ApplicationName = 1000,
Start,
Stop,
Pause,
Save,
Discard,
SelectRunway,
DoAlignment,
RedoAlignment,
AlignmentOK,
DoCalibrationStage1,
SetCalibrationStage1,
SetCalibrationStage2,
SetCalibrationStage3,
CancelCalibration,
CalibrationOK
};
struct Alignment{
int x;
int y;
int error;
};
struct Calibration{
int x;
int y;
int error;
};
}
alignment and calibration are the two internal message structures.
What I'm trying to do is build a 'message interpreter' which will receive an XML string, decode it and return any one of the structs shown above; so if the <messageType> is 'alignment', the message interpreter will build an alignment struct, and return that.
So ultimately, I'm trying to make a template function, which can return an arbitrary struct, based on what i read in from <messageType>.
Are my objectives clear? is my approach the right one?
Let me know if I should clarify, or if I should take a different approach.
I don't believe a template function makes sense. Your input is always going to be a string, and C++ can't differentiate function signatures based on return type alone - so I don't know how a template would help - what would the type argument be?
I'd suggest making your function a normal one that parses out the messageType and allocates a struct based on it - you can use whatever constructs you want for this.
The trick would be (in my mind) to derive all of your internal-message-classes from the same empty base class - you could then return a pointer to that base class back from your function, and it will hold whatever type got created.
It be a good idea to return an enumeration along with the pointer in a std::pair which you can use to determine the correct derived type that was created, that way you can cast the result directly to the correct derived type with a static_cast.
As I understand it your structures are known within the application, so what about this save variant:
class Message {
public:
static Message Alignment (alignment_t const &);
...
Type type() const;
int alignment() const;
private:
Message (Type t);
assert_type (Type t, const char *msg) const;
private:
Type type_;
};
Message Message::Alignment (alignment_t const &alignment)
{
Message ret (Type::Alignment);
ret.alignment_ = alignment;
return ret;
}
void Message::assert_type (Type t, const char *msg) const
{
if (type() != t) throw std::runtime_error (msg);
}
int Message::alignment() const
{
assert_type (Type::Alignment,
"alignment_x() called for non-alignment-message");
return alignment_;
}
(coded without verification to give you the idea)
This works without polymorphism (I use this pattern in a compiler for a LISP like language, where polymorphic trees would result in more complicated code). You can change it to return "alignment_x()" and so on, if you like that more.
Fully dynamic structures are not possible, and solutions that try to come near will be rather complicated. Use the most-maintainable solution.
If you write a factory function/functor for each type, you can associate that with the messageType (map<string, Factory*> will be sufficient), but what to return?
You can return some kind of discriminated union, or boost::variant, if you don't mind the top-level decoder depending on all possible message types.
But, what is the decoder going to do with this return value? If it just switches on the type and calls a type-specific callback in each case, you could invert control by attaching a callback function/functor to the factory directly.
Then the decoder doesn't return anything, it just constructs the message struct and passes it directly to a handler.
Simple implementation (OK, that was more typing than I thought):
class Decoder
{
public:
virtual ~Decoder();
virtual void decode(std::string const &xml) = 0;
};
template <typename Factory, typename Callback>
class SimpleDecoder: public Decoder
{
Factory factory;
Callback callback;
public:
SimpleDecoder(Factory f, Callback c)
: factory(f), callback(c)
{}
void decode(std::string const &xml)
{
callback( factory( xml ) );
}
};
std::map<std::string, Decoder*> factories;
template <typename F, typename C>
void registerSimpleDecoder(std::string const &n, F f, C c)
{
factories[n] = new SimpleDecoder(f, c);
}
void decodeXmlMessage(std::string const &messageType, std::string const &body)
{
factories[messageType]->decode(body);
}
using QMetaObject::newInstance, so you can create a QObject* that can be converted afterwards to your class using dynamic_cast
class MyClass : public QObject{
public:
enum Type{ MyClassType = UserType + 1 }
Q_INVOKABLE MyClass();
}
Q_DECLARE_METATYPE ( MyClass )
then, in your XML Parsing Code:
MyClass* myObject = (MyClass*) QMetaType::construct ( MyClass::MyClassType );
And things will work out.
Related
I have some code that accepts one type of object and creates another type of object based on the type of the first. (There is a 1->1 relationship between the types.) I originally used a hash table (unordered_map<>) with a key based on the type of the first object to associate a creation function for the second object. But as I am learning more about the C++ features introduced since the last time I was full-time C++, I discovered std::variant<>.
I have successfully converted the implementation to use this C++17 feature. However, there is one remaining piece that is still a bit cumbersome. The design makes a call to a static member function of the second class to validate the contents of the first object, before instantiating an object of the second class. To handle this right now, I'm using a visitor structure with function operators overloaded for each input type.
What I'm wondering is if there is some way to use a template for the association, rather than the copied code with only the types different?
I've tried looking at the way std::variant<> works, and I see where the index of the type can be obtained with .index(). I can see how to instantiate an object based on an index, which I might use if I created a second std::variant<> with the object types. But, as you can see, I don't want to instantiate the object until the parameters have been validated. The function that does that is static, and I don't see a way to associate the parms type with the object type in a way that lets me make the static call.
(I also realize that these two visitor structures can be combined in the code below, but in the real code, the creation is longer and more complicated, and I would rather not have copies of it in each overload.)
struct Type1Parms {};
struct Type2Parms {};
struct Type3Parms {};
...
struct TypeBase {};
struct Type1 : public TypeBase
{
static bool ValidateParms(const Type1Parms&);
Type1(const Type1Parms&);
};
struct Type2 : public TypeBase
{
static bool ValidateParms(const Type2Parms&);
Type2(const Type2Parms&);
};
struct Type3 : public TypeBase
{
static bool ValidateParms(const Type3Parms&);
Type3(const Type3Parms&);
};
...
struct ValidateParmsVisitor
{
bool operator()(const Type1Parms& parms)
{
return Type1::ValidateParms(parms);
}
bool operator()(const Type2Parms& parms)
{
return Type2::ValidateParms(parms);
}
bool operator()(const Type3Parms& parms)
{
return Type3::ValidateParms(parms);
}
...
};
using TypeParms = std::variant<Type1Parms, Type2Parms, Type3Parms, ...>;
struct CreateObjectVisitor
{
std::unique_ptr<TypeBase> operator()(const Type1Parms& parms)
{
return std::make_unique<Type1>(parms);
}
std::unique_ptr<TypeBase> operator()(const Type2Parms& parms)
{
return std::make_unique<Type2>(parms);
}
std::unique_ptr<TypeBase> operator()(const Type3Parms& parms)
{
return std::make_unique<Type3>(parms);
}
...
};
template<typename TParms>
std::unique_ptr<TypeBase> CreateType(const TParms& parms)
{
unique_ptr<TypeBase> obj;
if (visit(ValidateParmsVisitor{}, parms))
obj = visit(CreateObjectVisitor{}, parms);
return std::move(obj);
}
Is there a way to make this association, especially as a type that can be used with a static member function call?
EDIT: I should explain that this is part of a much larger project, with a number of other design criteria that shape its design.
For example, this is for a client interface, where the API is meant to be as simple as can be expressed. The client only has visibility (via header) to the parms structures and a function that takes the parms & returns an object that contains the objects mentioned above. The original design did indeed have a base structure for the parms, which obviously had to be in the public header. However, this meant that a client could inherit from the base class themselves and pass this into the object creation function, or inherit from the acceptable structures. To avoid segfaults, this necessitated adding runtime checks to be sure the types were acceptable, which was mostly handled by the hash design--although it wasn't quite that simple. When I removed the hash design, I also lost this method of type validation, but I recognized that this would be replaced by a compile time check with the variant<>, handling custom structures (no base to check now). I also learned about the C++ version of the final keyword which handled the inheritance issue.
Additionally, while the code above does not show it, the parms structures contain multiple members and the ValidateParms() functions actually attempt to validate whether the values and combinations are valid.
You can create traits for the association:
template <typename T> struct from_param;
template <> struct from_param<Type1Parms> { using type = Type1; };
template <> struct from_param<Type2Parms> { using type = Type2; };
template <> struct from_param<Type3Parms> { using type = Type3; };
Then, you might do
using TypeParms = std::variant<Type1Parms, Type2Parms, Type3Parms>;
std::unique_ptr<TypeBase> CreateType(const TypeParms& parms)
{
if (std::visit([](const auto& param){
return from_param<std::decay_t<decltype(param)>>::type::ValidateParms(parms);
}, parms))
{
return std::visit([](const auto& param) -> std::unique_ptr<TypeBase> {
return std::make_unique<typename from_param<std::decay_t<decltype(param)>>::type>(parms);
}, parms);
}
return nullptr;
}
Demo
or without variant, if you call with correct type:
template <typename T>
auto CreateType(const T& parms)
{
if (from_param<T>::type::ValidateParms(parms))
{
return std::make_unique<typename from_param<T>::type>(parms);
}
return nullptr;
}
There is a very simple method, a set of overloaded functions:
unique_ptr<TypeBase> CreateType(Type1Params const& params)
{
return make_unique<Type1>(params);
}
unique_ptr<TypeBase> CreateType(Type2Params const& params)
{
return make_unique<Type2>(params);
}
unique_ptr<TypeBase> CreateType(Type3Params const& params)
{
return make_unique<Type3>(params);
}
Notes:
You can add another overload to catch other parameters and then return null, but I think a compile-time error would be preferable.
You could also use a template function and specializations, but there's probably little typing to safe that way.
I'm about to design a config-reader which reads data from a file. The data in file may be different types like int/float/string ...
I hope the config-reader has a simple interface, so people can easily use it.
First, I wrote listed all the types
enum class DataType { INT, UINT32, UINT64, FLOAT, STRING, ARRAY, USER_TYPE, BADTYPE };
Then, I wrote the "base" class for all types
class BasicType{
public:
DataType value_type;
public:
BasicType() : value_type(DataType::USER_TYPE){}
virtual bool parse(const string& ) {}
virtual string toString(){ return ""; }
};
Then, I continue writing each specific type implementations, something like
template <int _type>
class BuildInType: public BasicType
{
private:
// TODO replace this with boost variant or so
int value_int;
uint32_t value_uint32;
uint64_t value_uint64;
float value_float;
string value_string;
public:
BuildInType() {
value_type = static_cast<DataType>(_type);
}
void bool parse(const string& data_field){ ... }
};
typedef BuildInType < static_cast<int>(DataType::INT) > IntType;
typedef BuildInType < static_cast<int>(DataType::UINT32) > Uint32Type;
typedef BuildInType < static_cast<int>(DataType::UINT64) > Uint64Type;
...
Here Let's just forget Array-type and USER-Defined type
And for the interface,
class Parser{
...
BasicType* read_next(){
//The parse will read the data from file
//and return something like &IntType, &FloatType or so
};
Parser p("some file");
while(true){
BasicType* b = p.read_next();
if(!b)break;
// Here I'm trying to convert BaseType back to IntType/FloatType etc,
// because I want to fetch value_int/value_float ... defined in these derived-classes
}
Here after read_next(), we get a BasicType pointer which points to its derived class. Here I want to recover the orignal derived class. there any good way to do the "conversion"? or if there're any better ways for this problem?
Thank you!
Here I want to recover the orignal derived class.
if (const IntType* p = dynamic_cast<const IntType*>(b))
do something with p->value_int;
else ...
if there're any better ways for this problem?
Hard to say given no background on your robustness/performance/memory-usage etc. requirements, why you're not storing them in the actual type as they're read (i.e. type-safe "deserialisation"), why you're not using an existing library etc.. Anyway, in a similar space you might like to Google for docs on boost::variant and/or boost::lexical_cast - they can be helpful for similar storage/conversions.
So I am using this telegram/message dispatcher system for my A.I. which comes from Matt Buckland's "Programming Game A.I. by Example" book.
I have this method for the MessageDispatcher class:
void DispatchMsg(double delay, int sender, int receiver, int msg, void *additionalInfo = nullptr);
Which then uses a Telegram struct:
struct Telegram
{
// Messages can be either dispatched immediately or delayed for
// a specified amount of time. If a delay is necessary, this
// field is stamped with the time the message should be dispatched.
double DispatchTime;
// Who is sending this message
int Sender;
// Who should the component give this message to
// may be set to -1 if not required
int Receiver;
// Message itself, should be one of the several enumerated types
int Msg;
// Additional information that might want to be passed along
void *ExtraInfo;
Telegram():DispatchTime(-1),
Sender(-1),
Receiver(-1),
Msg(-1)
{
// Empty
}
Telegram(double time,
int sender,
int receiver,
int msg,
void *info = nullptr):DispatchTime(time),
Sender(sender),
Receiver(receiver),
Msg(msg),
ExtraInfo(info)
{
// Empty
}
};
With a cast like:
template <class T>
inline T DereferenceToType(void *p)
{
return *(T*)(p);
}
The trouble lies here:
void Player::playerFeed() {
if (!Target)
return;
Courier->DispatchMsg(SEND_MSG_IMMEDIATELY, PLAYER_ID, TargetedActor, MessageType::PLAYER_FED, &ActorNode->getPosition());
}
Where ActorNode->getPosition() is from Ogre3d Ogre::SceneNode:
virtual const Vector3 & getPosition (void) const
Gets the position of the node relative to it's parent.
I then get it back doing:
Ogre::Vector3 attackerPos = DereferenceToType<Ogre::Vector3>(msg.ExtraInfo);
I would prefer to use a const Ogre::Vector3 here and that can be done writing a const dereference helper function.
Anyway, the problem is:
xxx|90|warning: invalid conversion from 'const void*' to 'void*' [-fpermissive]|
I understand the warning; but I'm not sure how to correct the problem.
I tried fixing it by writing a second method for DispatchMsg:
void DispatchMsg(double delay, int sender, int receiver, int msg, void *additionalInfo = nullptr);
// For const void*
void DispatchMsg(double delay, int sender, int receiver, int msg, const void *additionalInfo);
But that moved the warning into the function at the creation of the Telegram.
So I tried some things like making a second parameter in my Telegram structure called const void *ConstExtraInfo, the trouble is this seems to make the Telegram structure messy imo.
Basically my question is: is there a clean way implementation for this or if it must be done by having extra members within the Telegram to find out which type of information is stored?
Can it be done with a template for void* or const void* like: Telegram or would this complicate the receiving end of the telegram?
Please let me know if I need to post more information on this.
Thanks.
Your first problem is that the additionalInfo-pointer should be const-qualified.
Then, your template should also use const.
Finally, it should return a reference and not copy the data:
template <class T> inline const T& DereferenceToType(const void *p)
{
return *(const T*)p;
}
Anyway, why hide the cast? Instead, do it like this in the receipient:
const auto& extra = *(T*)p;
You could use a const_cast or a plain C style cast to throw away const. This would be the quickest and dirtiest way.
Now, what you are really trying to achieve here is to covert to an intermediate data type that can be cast back and forth from an abstract type to a concrete type. One possible way of doing this is to use what some refer to as a Variant, which is a class/struct that holds some opaque data and a tag that identifies this data. Something similar to:
enum DataTag {
DATA_INT,
DATA_STRING,
DATA_VEC3,
// etcetera
};
struct Variant {
virtual DataTag GetTypeTag() const = 0;
virtual int AsInt() const = 0;
virtual string AsString() const = 0;
virtual Vec3 AsVector() const = 0;
// same goes for assigning a value. I.e: FromInt()/FromString()
};
template<class T>
struct VariantImpl : public Variant {
// add constructors as needed
VariantImpl(const T & data, DataTag tag)
{
this->data = data;
this->tag = tag;
}
// implement the proper conversions
int AsInt() const { }
string AsString() const { }
Vec3 AsVector() const { }
DataTag GetTypeTag() const { return tag; }
T data;
DataTag tag;
};
Then you could have a pointer to a Variant in the Telegram struct and set the ExtraInfo with:
telegram->ExtraInfo = new VariantImpl<int>(42);
And then access it at any time with AsInt(), as long as you check the type tag first to ensure the conversion is allowed.
From this, you can add a lot to it to fit your needs. Hope it helps.
I need to pass in a type to a class. The code below works but I was wondering if it is the best way to do this. Are there better ways?
template<typename T, typename M>
class BinaryParser
{
public:
BinaryParser(T& decoder, unsigned header_size)
: m_decoder(decoder), m_header_size(header_size) {}
virtual bool Parse() {
M message;
//do something with message
return true;
}
protected:
T& m_decoder;
unsigned m_header_size;
};
int main(int argc, char* argv[])
{
int a1, b1;
a1=1;
b1=2;
BinaryParser<int,string> bp(a1,b1);
bp.Parse();
return 0;
}
You don't have to make the Parse member function virtual if you are not re-implementing it in sub-classes (as it seems from your example code). Instead you can provide a template method. You would probably want to require template parameter type to have some defined interface:
template <typename M>
bool Parse() {
M message; // M must be default constructable
// ... parse message from a stream or something
m_decoder.decode( message.getBytes()); // M must have getBytes() member
return message.isValid(); // M must have isValid() member
}
Then use it like:
BinaryParser<int> bp(a1,b1);
if ( bp.Parse<string>()) { /* parsed */ }
if ( bp.Parse<some_other_type>()) { /* parsed */ }
Since C++ is a statically typed language with very limited type introspection capabilities, using templates is the best way to pass a type to a class, and the only way to let a class create new instances of a type. An alternative would be to pass typeid, but it would not work for your example, because it does not let you define new instances.
I've got a list of types which can be send over the network, take this example:
enum types {
E_T1,
E_T2,
E_T3,
E_T4
};
Now I have a list of classes which correspond to each of the types, let's say each is declared as class E_T1 {...}, class E_T2 {...}, etc.
They are not derived from a common base class and it's not possible to do so. Each of the classes has a verification method I need to invoke with the data send over the network. The client sends the data D and a id correspointing to the message type. I need to get hold of the object corresponding to the type. I can use C++0x features if needed.
What I've tried so far is using specialized templates for the types, holding a typedef for the object related to it. This was obviously a stupid idea as templates parameters need to be compile time constant so doing something along getType<data.id()>::type is not possible.
Then I tried using Boost.Variant to get a common returnable type like this (used mpl vector to iterate over the registered types at runntime for debbuging):
template <typename C>
struct getType() {
typedef C type;
}
typedef boost::mpl::vector<
getType<E_T1>,
getType<E_T2>,
getType<E_TX>...
> _types;
typedef boost::make_variant_over<_types>::type _type;
//use a map to store each type <-> id
boost::unorderd_map<types, _type> m;
m[E_T1] = getType<E_T1>();
m[data.id()]::type x; //<- access type, can now call x.validate(data)
The problem with this is that it's limited to 20 entries per variant per default. This can be overwritten but from what I understood the overhead per type should be considered and we are talking about a few thousand types here.
Also tried boost.any but it doesn't hold any type information so that's out of the question again. Has anyone any good ideas how this can be solved elegantly?
Looking for something where I don't have to write a 1k switch statement anytime I handle a type.
All types are nown at compile type, same goes for their corresponding IDs.
Id -> Type resolving needs to happen at runtime though.
Thanks in advance,
Robin.
External Polymorphism (*)
It's a widely known idiom, however it's widely used: I first encountered it in the shared_ptr implementation and it's been quite useful in my toolbox.
The idea is to actually create a base class for all those types. But not having them derive from it directly.
class Holder {
public:
virtual ~Holder() {}
virtual void verify(unsigned char const* bytes, size_t size) const = 0;
}; // class Holder
template <typename T>
class HolderT: public Holder {
public:
HolderT(): _t() {}
virtual void verify(unsigned char const* bytes, size_t size) const {
_t.verify();
}
private:
T _t;
}; // class HolderT
template <typename T>
std::unique_ptr<Holder> make_holder() {
return std::unique_ptr<Holder>(new HolderT<T>());
}
So, it's the classic strategy of adding a new level of indirection.
Now, you obviously do need a switch to move from value to class. Or perhaps... a map ?
using maker = std::unique_ptr<Holder> (&)();
using maker_map = std::unordered_map<types, maker>;
std::unique_ptr<Holder> select(types const E) {
static maker_map mm;
if (mm.empty()) {
mm.insert(std::make_pair(E_T1, make_holder<EC_T1>));
// ...
}
maker_map::const_iterator it = mm.find(E);
if (it == mm.end()) { return std::unique_ptr<Holder>(); }
return (*it->second)();
}
And now you can handle them polymorphically:
void verify(types const E, unsigned char const* bytes, size_t size) {
std::unique_ptr<Holder> holder = select(E);
if (not holder) { std::cerr << "Unknown type " << (int)E << "\n"; return; }
holder->verify(bytes, size);
}
Of course, you're welcome to make the strategy vary according to your needs. For example moving the map out of select so that you can register your types dynamically (like for plugins).
(*) At least that's the name I have for it, I would quite happy to find out it's already been named.
I'll assume you have a generic way of handling a message, such as for example an overloaded function:
void handle_message(const E_T1& msg);
void handle_message(const E_T2& msg);
//...
Now, you do not really need to get the object's type. All you need is a way to handle a message of that type, given the undecoded message.
So, I recommend you populate a map of factory functions:
std::unordered_map<types, std::function<void (unsigned char const* bytes, size_t size)> handlers;
handlers[E_E1] = [](unsigned char const* bytes, size_t size) { handle_message(E_T1(bytes, size)); };
// ...
Then, once you've decoded the type, you can use handlers[type](bytes, size) to decode and handle a message.
Try variadic templates and your already defined getType class:
enum types { T1_ID, T2_ID, .... };
class T1; class T2; class T3; ....
template <types t> struct getType;
template <> struct getType<T1_ID> { typedef T1 type; };
template <> struct getType<T2_ID> { typedef T2 type; };
...
And the operation verify:
template <types...>
struct type_operation;
template <types t1, types... rest>
struct type_operation<t1, rest...>
{
void verify(types t)
{
if (t == t1)
{
typename getType<t1>::type a;
a.verify(); // read from network and verify the rest of data....
}
else type_operation<rest...>::verify(t, data);
}
};
template <>
struct type_operation<>
{
void verify(types t)
{
ostringstream log; log << "not suppoted: " << t;
throw std::runtime_error(log.str()); //
}
};
Usage:
typedef type_operation<T1_ID, T2_ID, T3_ID, ,,.., TN_ID> type_mapping;
types id;
readFromNetwork(id);
type_mapping::verify(id);