Templates without T parameters in a non-template class - c++

Ok, I read a lot of answers here and there about this problem, but probably since I don't know the proper syntax I can't figure out how to do this.
I have a non-template class which has to implement different static utility functions, mainly for serialization and deserialization. What I currently have is something like this:
class Data_Base : public QObject
{
...
protected:
static QByteArray Serialize(int value);
static int DeserializeInt(QByteArray ser);
static QByteArray Serialize(char *value);
static char *DeserializeCharArr(QByteArray ser);
static QByteArray Serialize(QString value);
static QString DeserializeQString(QByteArray ser);
....
}
Now, I'd prefer to have all the Deserialize* function as a template, since it will be nicer. And as a bonus, have also the Serialize functions as templates, so I will force the user to actually explicitely say which overload to call. Something which can be used this way:
QByteArray ba = Serialize<int>(5);
...
int theValue = Deserialize<int>(ba);
Now, I've tried different approaches, but since all the functions I saw only examples implementing the templates automatically and not one overload at a time I couldn't find out how to make this work.
Of course this is C++, with QT additions.

As stated in the comments, it is called template specialization and looks like this:
class X
{
public:
template<typename T>
static QByteArray Serialize(T const& t);
template<typename T>
static T Deserialize(QByteArray& v);
};
template<>
QByteArray X::Serialize(int const& t)
{
/* ... */
}
template<>
QByteArray X::Serialize(QString const& t)
{
/* ... */
}
template<>
int X::Deserialize(QByteArray& v)
{
/* ... */
}
template<>
QString X::Deserialize(QByteArray& v)
{
/* ... */
}
QByteArray x=X::Serialize(5);
int y=X::Deserialize<int>(x);
When using Serialize you do not need to specify the template parameter because it can be deduced from the argument's
type.
But you cannot deduce by return type, so you need to add the template parameter when using Deserialize.

IMO force your solution with the usage of template specialization could be a bad choice design.
As I've already said in a comment, templates are generally good when your code structure is equal for each data type.
Serialization is a delicate operation (casting, raw memory, etc.) and data structure can define different implicit conversions and produce an UB.
If I had to implement an a "template" behaviour, this would be the first solution (just a scratch!):
struct Foo {
// Some data member variables.
std::string m_nopod;
// Serialize data object. 'It' must to be a output iterator
template<typename It>
void serialize(It out_iterator) {
constexpr size_t BYTES_FOR_SIZE = sizeof(decltype(m_nopod.size()));
constexpr size_t BYTES_FOR_CHAR = sizeof(decltype(m_nopod)::value_type);
// size definitions.
const auto len_str = m_nopod.size();
const auto len_data = BYTES_FOR_CHAR * len_str;
// Temporary memory buffers.
uint8_t memory_size[BYTES_FOR_SIZE];
auto memory_data = std::make_unique<uint8_t[]>(len_data);
// Raw bytes copy.
std::memcpy(memory_size, &len_str, BYTES_FOR_SIZE);
std::memcpy(memory_data.get(), m_nopod.data(), len_data);
// write with the iterator.
for (size_t i = 0; i < BYTES_FOR_SIZE; ++i) {
*out_iterator = memory_size[i];
}
for (size_t i = 0; i < len_data; ++i) {
*out_iterator = memory_data[i];
}
}
};
Where the out_iterator must to be a output_iterator, and ::value_type must to be a implicit convertible type to unsigned char.
The function can be invoked with different data structures (containers):
int main(int argc, char *argv[]) {
std::vector<char> memory_buffer_char;
std::vector<int> memory_buffer_int;
std::string memory_buffer_str;
Foo foo{"a_string"};
foo.serialize(std::back_inserter(memory_buffer_char));
foo.serialize(std::back_inserter(memory_buffer_int));
foo.serialize(std::back_inserter(memory_buffer_str));
return 0;
}
As I've already said, however, I'll never adopt that solution. Rather I'm going to use a simple overloading of function for those various types.
In order avoid writing same thing more than once, I'll define a unique helper function (a private method) which contains the logic of the class.
For example the helper function could create an ordinary buffer of memory in which to serialize the class (array of char) and then overloaded functions should only adapt that array in the proper input data structure.
In that way when the class logic (e.g., data members) changes, you should modify only the helper function.

Related

Can static polymorphism (templates) be used despite type erasure?

Having returned relatively recently to C++ after decades of Java, I am currently struggling with a template-based approach to data conversion for instances where type erasure has been applied. Please bear with me, my nomenclature may still be off for C++-natives.
This is what I am trying to achieve:
Implement dynamic variables which are able to hold essentially any value type
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to hold variable instances in containers, independent of their value type
Convert between variable value and representation using conversion functions
Be able to introduce new representations just by providing new conversion functions
Constraints: use only C++-11 features if possible, no use of libraries like boost::any etc.
A rough sketch of this might look like this:
#include <iostream>
#include <vector>
void convert(const std::string &f, std::string &t) { t = f; }
void convert(const int &f, std::string &t) { t = std::to_string(f); }
void convert(const std::string &f, int &t) { t = std::stoi(f); }
void convert(const int &f, int &t) { t = f; }
struct Variable {
virtual void get(int &i) = 0;
virtual void get(std::string &s) = 0;
};
template <typename T> struct VariableImpl : Variable {
T value;
VariableImpl(const T &v) : value{v} {};
void get(int &i) { convert(value, i); };
void get(std::string &s) { convert(value, s); };
};
int main() {
VariableImpl<int> v1{42};
VariableImpl<std::string> v2{"1234"};
std::vector<Variable *> vars{&v1, &v2};
for (auto &v : vars) {
int i;
v->get(i);
std::string s;
v->get(s);
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
return 0;
}
The code does what it is supposed to do, but obvoiusly I would like to get rid of Variable::get(int/std::string/...) and instead template them, because otherwise every new representation requires a definition and an implementation with the latter being exactly the same as all the others.
I've played with various approaches so far, like virtual templated, methods, applying the CRDT with intermediate type, various forms of wrappers, yet in all of them I get bitten by the erased value type of VariableImpl. On one hand, I think there might not be a solution, because after type erasure, the compiler cannot possibly know what templated getters and converter calls it must generate. On the other hand I think i might be missing something really essential here and there should be a solution despite the constraints mentioned above.
This is a classical double dispatch problem. The usual solution to this problem is to have some kind of dispatcher class with multiple implementations of the function you want to dispatch (get in your case). This is called the visitor pattern. The well-known drawback of it is the dependency cycle it creates (each class in the hierarchy depends on all other classes in the hierarchy). Thus there's a need to revisit it each time a new type is added. No amount of template wizardry eliminates it.
You don't have a specialised Visitor class, your Variable serves as a Visitor of itself, but this is a minor detail.
Since you don't like this solution, there is another one. It uses a registry of functions populated at run time and keyed on type identification of their arguments. This is sometimes called "Acyclic Visitor".
Here's a half-baked C++11-friendly implementation for your case.
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <utility>
#include <functional>
#include <string>
#include <stdexcept>
struct Variable
{
virtual void convertValue(Variable& to) const = 0;
virtual ~Variable() {};
virtual std::type_index getTypeIdx() const = 0;
template <typename K> K get() const;
static std::map<std::pair<std::type_index, std::type_index>,
std::function<void(const Variable&, Variable&)>>
conversionMap;
template <typename T, typename K>
static void registerConversion(K (*fn)(const T&));
};
template <typename T>
struct VariableImpl : Variable
{
T value;
VariableImpl(const T &v) : value{v} {};
VariableImpl() : value{} {}; // this is needed for a declaration of
// `VariableImpl<K> below
// It can be avoided but it is
// a story for another day
void convertValue(Variable& to) const override
{
auto typeIdxFrom = getTypeIdx();
auto typeIdxTo = to.getTypeIdx();
if (typeIdxFrom == typeIdxTo) // no conversion needed
{
dynamic_cast<VariableImpl<T>&>(to).value = value;
}
else
{
auto fcnIter = conversionMap.find({getTypeIdx(), to.getTypeIdx()});
if (fcnIter != conversionMap.end())
{
fcnIter->second(*this, to);
}
else
throw std::logic_error("no conversion");
}
}
std::type_index getTypeIdx() const override
{
return std::type_index(typeid(T));
}
};
template <typename K> K Variable::get() const
{
VariableImpl<K> vk;
convertValue(vk);
return vk.value;
}
template <typename T, typename K>
void Variable::registerConversion(K (*fn)(const T&))
{
// add a mutex if you ever spread this over multiple threads
conversionMap[{std::type_index(typeid(T)), std::type_index(typeid(K))}] =
[fn](const Variable& from, Variable& to) {
dynamic_cast<VariableImpl<K>&>(to).value =
fn(dynamic_cast<const VariableImpl<T>&>(from).value);
};
}
Now of course you need to call registerConversion e.g. at the beginning of main and pass it each conversion function.
Variable::registerConversion(int_to_string);
Variable::registerConversion(string_to_int);
This is not ideal, but hardly anything is ever ideal.
Having said all that, I would recommend you revisit your design. Do you really need all these conversions? Why not pick one representation and stick with it?
Implement dynamic variables which are able to hold essentially any value type
Be able to hold variable instances in containers, independent of their value type
These two requirements are quite challenging on its own. The class templates don't really encourage inheritance, and you already did the right thing to hold what you asked for: introduced a common base class for the class template, which you can later refer to in order to store pointers of the said type in a collection.
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to introduce new representations just by providing new conversion functions
This is where it breaks. Function templates assume common implementation for different types, while inheritance assumes different implementation for the same types.
You goal is to introduce different implementation for different types, and in order to make your requirements viable you have to switch to one of those two options instead (or put up with a number of functions for each case which you have already introduced yourself)
Edit:
One of the strategies you may employ to enforce inheritance approach is generalisation of the arguments to the extent where they can be used interchangeably by the abstract interface. E.g. you may wrap the converting arguments inside of a union like this:
struct Variable {
struct converter_type {
enum { INT, STRING } type;
union {
int* m_int;
std::string* m_string;
};
};
virtual void get(converter_type& var) = 0;
virtual ~Variable() = default;
};
And then take whatever part of it inside of the implementation:
void get(converter_type& var) override {
switch (var.type) {
case converter_type::INT:
convert(value, var.m_int);
break;
case converter_type::STRING:
convert(value, var.m_string);
break;
}
}
To be honest I don't think this is a less verbose approach compared to just having a number of functions for each type combination, but i think you got the idea that you can just wrap your arguments somehow to cement the abstract class interface.
Implement std::any. It is similar to boost::any.
Create a conversion dispatcher based off typeids. Store your any alongside the conversion dispatcher.
"new conversion functions" have to be passed to the dispatcher.
When asked to convert to a type, pass that typeid to the dispatcher.
So we start with these 3 types:
using any = std::any; // implement this
using converter = std::function<any(any const&)>;
using convert_table = std::map<std::type_index, converter>;
using convert_lookup = convert_table(*)();
template<class T>
convert_table& lookup_convert_table() {
static convert_table t;
return t;
}
struct converter_any: any {
template<class T,
typename std::enable_if<
!std::is_same<typename std::decay<T>::type, converter_any>::value, bool
>::type = true
>
converter_any( T&& t ):
any(std::forward<T>(t)),
table(&lookup_convert_table<typename std::decay<T>::type>())
{}
converter_any(converter_any const&)=default;
converter_any(converter_any &&)=default;
converter_any& operator=(converter_any const&)=default;
converter_any& operator=(converter_any&&)=default;
~converter_any()=default;
converter_any()=default;
convert_table const* table = nullptr;
template<class U>
U convert_to() const {
if (!table)
throw 1; // make a better exception than int
auto it = table->find(typeid(U));
if (it == table->end())
throw 2; // make a better exception than int
any const& self = *this;
return any_cast<U>((it->second)(self));
}
};
template<class Dest, class Src>
bool add_converter_to_table( Dest(*f)(Src const&) ) {
lookup_convert_table<Src>()[typeid(Dest)] = [f](any const& s)->any {
Src src = std::any_cast<Src>(s);
auto r = f(src);
return r;
};
return true;
}
now your code looks like:
const bool bStringRegistered =
add_converter_to_table(+[](std::string const& f)->std::string{ return f; })
&& add_converter_to_table(+[](std::string const& f)->int{ return std::stoi(f); });
const bool bIntRegistered =
add_converter_to_table(+[](int const& i)->int{ return i; })
&& add_converter_to_table(+[](int const& i)->std::string{ return std::to_string(i); });
int main() {
converter_any v1{42};
converter_any v2{std::string("1234")};
std::vector<converter_any> vars{v1, v2}; // copies!
for (auto &v : vars) {
int i = v.convert_to<int>();
std::string s = v.convert_to<std::string>();
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
}
live example.
...
Ok, what did I do?
I used any to be a smart void* that can store anything. Rewriting this is a bad idea, use someone else's implementation.
Then, I augmented it with a manually written virtual function table. Which table I add is determined by the constructor of my converter_any; here, I know the type stored, so I can store the right table.
Typically when using this technique, I'd know what functions are in there. For your implementation we do not; so the table is a map from the type id of the destination, to a conversion function.
The conversion function takes anys and returns anys -- again, don't repeat this work. And now it has a fixed signature.
To add support for a type, you independently register conversion functions. Here, my conversion function registration helper deduces the from type (to determine which table to register it in) and the destination type (to determine which entry in the table), and then automatically writes the any boxing/unboxing code for you.
...
At a higher level, what I'm doing is writing my own type erasure and object model. C++ has enough power that you can write your own object models, and when you want features that the default object model doesn't solve, well, roll a new object model.
Second, I'm using value types. A Java programmer isn't used to value types having polymorphic behavior, but much of C++ works much better if you write your code using value types.
So my converter_any is a polymorphic value type. You can store copies of them in vectors etc, and it just works.

Serialization of simple structures without external libraries

I'm trying to serialize simple single level classes like the ones bellow, without external libraries like boost, and without having to implement serializer function for every class. Even though I have so few classes that I could easily implement a serializer for each one, for future reference, I would like to have at hand a simple solution that scales well.
The requirement for each class to be serialized is that its members are only serializable types, and an array of member pointers is defined, so that at serialization the members can be iterated regardless of which class is passed.
The problem is that the compilation fails because of the missing cast where the member pointer is dereferenced, obviously:
esp32.ino: 122:35: error: 'footprint.MessageFootprint<1>::Members[i]'
cannot be used as a member pointer, since it is of type 'void*
I don't know how to store the member pointers in a iterable collection or how to avoid the void* cast.
That's my goal. I want to iterate over class members at serialization having a single generic serialization function.
I don't know what to do.
enum SerializableDataTypes {
SerInt,
SerFloat,
SerString,
SerIntArray
};
template <int N>
struct MessageFootprint {
SerializableDataTypes DataTypes[N];
void* Members[N];
};
template<typename T, typename R>
void* void_cast(R(T::*m))
{
union
{
R(T::*pm);
void* p;
};
pm = m;
return p;
}
class ControlMessage{};
// first structure to be serialized
class Message1 : public ControlMessage {
public:
int prop1;
int prop2;
};
const int Message1MemberCount = 2;
const MessageFootprint<Message1MemberCount> Message1FootPrint = { { SerInt, SerInt }, {void_cast(&Message1::prop1), void_cast(&Message1::prop2)} };
// second structure to be serialized
class Message2 : public ControlMessage {
public:
int prop1;
String prop2;
};
const int Message2MemberCount = 2;
const MessageFootprint<Message2MemberCount> Message2FootPrint = { { SerInt, SerInt }, {void_cast(&Message2::prop1), void_cast(&Message2::prop2)} };
template<int N>
void SerializeMessage(MessageFootprint<N> footprint, ControlMessage message) {
for (int i = 0; i < N; i++) {
if (footprint.DataTypes[i] == SerInt) {
// serialization code here based on data type
// for demonstration purposes it's only written in the serial port
logLine(String(i));
Serial.println(*((int*)(message.*(footprint.Members[i]))));
}
}
}
void main() {
// usage example
Message1 msg = Message1();
msg.prop1 = 1;
msg.prop2 = 2;
SerializeMessage(Message1FootPrint, msg);
}
Don't erase types; that is, don't cast your pointers to void*. If you preserve the types of the pointers through templates, you can choose the deserialization functions directly off their types, and thus you won't even have to specify them. Indeed, you already have a bug where you have marked the second member of Message2 SerInt when it is a String. If you work off the actual types instead of forcing the user to duplicate them, you avoid such errors. Also, the common superclass is completely unnecessary.
template<typename T, typename... Parts>
struct MessageFootprint {
std::tuple<Parts T::*...> parts;
MessageFootprint(Parts T::*... parts) : parts(parts...) { }
};
template<typename T, typename... Parts>
MessageFootprint(Parts T::*...) -> MessageFootprint<T, Parts...>; // deduction guide
// e.g.
struct Message1 {
int prop1;
int prop2;
};
inline MessageFootprint footprint1(&Message1::prop1, &Message1::prop2);
// deduction guide allows type of footprint1 to be inferred from constructor arguments
// it is actually MessageFootprint<Message1, int, int>
// if you are on a C++ standard old enough to not have deduction guides,
// you will have to manually specify them
// this is still better than letting the types be erased, because now the compiler
// will complain if you get it wrong
// e.g. if I replicate your mistake
struct Message2 {
int prop1;
std::string prop2;
};
inline MessageFootprint<Message2, int, int> footprint2(&Message2::prop1, &Message2::prop2);
// This does not go through because ^^^ is wrong
Serialization is probably best handled with overloading. For each Part T::* in a MessageFootprint<T, Part...>, extract a Part& from the T and call out to an overloaded function that decides what to do based on Part:
// I have no idea what serial port communication stuff you're doing
// but this gets the point across
void SerializeAtom(int i) { std::cout << "I" << i; }
void SerializeAtom(std::string const &s) { std::cout << "S" << s.size() << "S" << s; }
template<typename T, typename... Parts>
void SerializeFootprint(MessageFootprint<T, Parts...> footprint, T const &x) {
// calls the provided functor with the things in the tuple
std::apply(
// this lambda is a template with its own Parts2... template parameter pack
// and the argument is really Parts2... parts
// we then do a fold expression over parts
// we need std::apply because there's no simpler way to get the actual
// values out (std::get fails when there are duplicates)
[&x](auto... parts) { (SerializeAtom(x.*parts), ...); },
footprint.parts);
}
// Trying to write ^^^ before C++17 would probably be a nightmare
This system is extensible: to add a new "atomic" type, just overload SerializeAtom. No need to manage an enum or whatnot. Deserialization would mean a family of DeserializeAtom overloads that write into the given reference, and a DeserializeFootprint which would probably look exactly like SerializeFootprint.
Godbolt demonstration
I've developed a serialization system that uses buffering.
Each object inherits from an interface that declares functions for:
1. Returning the size of the object on the stream.
2. Storing the object members to a buffer.
3. Loading the object members from a buffer.
This system is based on the fact that structs and classes can contain padding and that the class/struct is most knowledgeable about its members. For example, a multibyte integer may be Big Endian in the buffer, and the object needs to convert to Little Endian. This system also accommodates different methods for writing variable length text fields.
class Binary_Stream_Interface:
{
public:
// Returns the size, in uint8_t units, that the object occupies in
// a buffer (stream), packed.
virtual size_t size_on_stream() const = 0;
// Loads the class members from a buffer, pointed to by p_buffer.
// The p_buffer pointer will be incremented after loading the object.
virtual void load_from_buffer(uint8_t* & p_buffer) = 0;
// Stores the class members to a buffer, pointed to by p_buffer.
// The p_buffer pointer will be incremented after loading the object.
virtual void store_to_buffer(uint8_t * & p_buffer) const = 0;
};
To serialize (write) an object:
1. Call size_on_stream() to determine the buffer size needed.
2. Allocate the buffer.
3. Call store_to_buffer to store the object into the buffer.
4. Write the buffer to the stream, using std::ostream::write.
5. Delete the buffer.
Reading an object:
1. Call size_on_stream() to determine the buffer size needed.
2. Allocate the buffer.
3. Read the data from the stream into the buffer, using std::istream::read and the size needed.
4. Call the load_from_buffer() method.
5. Delete the buffer.
Implementation is left as an exercise for the OP.
Note: Templates can be used for common POD and std:string to make everything more uniform.
Edit 1: Example
struct Student
: public Binary_Stream_Interface
{
std::string name;
unsigned int id;
size_t size_on_stream() const
{
size_t stream_size = sizeof(id) + sizeof(int) + name.length();
return stream_size;
}
void load_from_buffer(uint8_t* & p_buffer)
{
// Read the string size.
unsigned int length = *((unsigned int *)(p_buffer));
p_buffer += sizeof(length);
// Load the string text from the buffer
name = std::string((char *) p_buffer, length);
p_buffer += length;
id = *((unsigned int *) p_buffer);
p_buffer += sizeof(id);
}
void store_to_buffer(uint8_t * & p_buffer) const
{
unsigned int length = name.length();
*((unsigned int *) p_buffer) = length;
p_buffer += sizeof(unsigned int);
p_char_buffer = (char *) p_buffer;
std::copy(name.begin(), name.end(), p_char_buffer);
p_buffer += length;
*((unsigned int *) p_buffer) = id;
p_buffer += sizeof(unsigned int);
}
};

How to pass in a type to a class

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.

Template classes C++ / Qt

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.

Universal function pointer

There is some class which have methods like:
int getSomething1();
std::string getSomething2();
someClass getSomething3();
There is structure which describes fields of this class like:
{"name of field", pointer to getter, std::type_info}
Then I would like to use it as follows:
if(type == int){
field_int = (int)getter();
}
else if(type == std::string){
field_string = (std::string)getter();
}
etc.
How to transform getters like
int getSomething1();
std::string getSomething2();
etc.
to some universal function pointer and then to get the correct value of field?
This answer of mine to another question addresses your problem pretty well. With some minor modifications, you get this:
template<class C, class T>
T get_attribute(const C& instance, T (C::*func)() const) {
return (instance.*func)();
}
Assuming the following:
struct Foo {
int getSomething1() const;
std::string getSomething2() const;
someClass getSomething3() const;
};
You can use it like this:
Foo foo;
int value = get_attribute<Foo, int>(foo, &Foo::getSomething1);
std::string value = get_attribute<Foo, std::string>(foo, &Foo::getSomething2);
someClass value = get_attribute<Foo, someClass>(foo, &Foo::getSomething3);
You can of course transform get_attribute to a functor to bind some or all of the arguments.
There is no formal universal function pointer, the equivalent of void*
for data. The usual solution is to use void (*)(); you are guaranteed
that you can convert any (non-member) function pointer to this (or any
other function pointer type) and back without loss of information.
If there is a certain similarity in the function signatures (e.g. all
are getters, with no arguments) and how they are used, it may be
possible to handle this with an abstract base class and a set of derived
classes (possibly templated); putting pointers to instances of these
classes in a map would definitely be more elegant than an enormous
switch.
What you are trying to achieve can be better achieved with already existing containers such as a boost fusion sequence. I'd advice that you try this first.
Templates to the rescue!
// Create mapping of type to specific function
template <typename T> T getSomething(); // No default implementation
template <> int getSomething<int>() { return getSomething1(); }
template <> std::string getSomething<std::string>() { return getSomething2(); }
template <> someClass getSomething<someClass>() { return getSomething3(); }
// Convenience wrapper
template <typename T> void getSomething(T& t) { t = getSomething<T>(); }
// Use
int i = getSomething<int>();
std::string s;
getSomething(s);
As I understand, your difficulty is in storing the function pointers, since they are of different types. You can solve this using Boost.Any and Boost.Function.
#include <boost/any.hpp>
#include <boost/function.hpp>
int getInt() {
return 0;
}
std::string getString() {
return "hello";
}
int main()
{
boost::function<boost::any ()> intFunc(getInt);
boost::function<boost::any ()> strFunc(getString);
int i = boost::any_cast<int>(intFunc());
std::string str = boost::any_cast<std::string>(strFunc());
}