I need to handle different elements in a vector, each element owning a specific parameter (integer or string), so that I can easily handle encoding/decoding of a series of elements.
-
Encoding a list of elements serializes the elements, inserting a separator in-between each.
-
Decoding a string consists in finding the separators then for each substring, extracting the ID and type-specific value. Example (knowing that "FOO" is associated to an integer and "BAR" is associated to a string): "FOO=54,BAR=hello" gives {{ID_FOO, 54}, {ID_BAR, "hello"}} .
I have the current following bare design:
#include <cstdint>
#include <cstdlib>
#include <string>
#include <memory>
enum eID { /*...*/ };
// Base class
class Base {
private:
enum eID m_Id;
public:
Base(enum eID = 0): m_Id(eID) {}
virtual std::string Encode() {
// Return encoding of m_Id
}
static Base* Decode(const std::string &str) {
Base *ptr;
// Extract id
// According to the kind of id, create a new Derived<T>
// giving the substring to the constructor
// ptr = new Derived<...>(id, str.substr(...));
return ptr;
}
};
template <class T>
class Derived<T> : public Base {
private:
T m_Value;
public:
Derived(enum eID id, const std::string &str); // participates to decoding
std::string Encode();
};
template<>
Derived<std::string>::Derived(enum eID id, const std::string &str) {
m_Value = str; // easy
}
template<>
std::string Derived<std::string>::Encode() {
return static_cast<Base*>(this)->Encode() + m_Value;
}
template<>
Derived<long>::Derived(enum eID id, const std::string &str) {
m_Value = strtol(str.c_str(), nullptr, 10);
}
template<>
std::string Derived<long>::Encode() {
// Encode id and integer param to a string
}
class BaseList {
private:
std::vector<std::unique_ptr<Base>> m_List;
public:
void Append(Base *ptr) {
m_List.push_back(std::unique_ptr<Base>(ptr));
}
std::string Encode() {
// Call each Encode() function and concatenate strings together
// Insert a delimiter in-between substrings
}
void Decode(const std::string &sToDecode) {
// Look for delimiters in sToDecode
// For each delimited substring:
// - call Base::Decode() to allocate a new type-specific object
// - push back into m_List
}
}
(This is not be a complete compiling example.)
Is it a logic design? How could it be optimized so that it may match any existing design pattern(s)? In particular I am concerned with the decoding technique, which here is split into BaseList::Decode() and the static method Base::Decode().
Best Answer
Ok, the actual question was about how to handle the difference between {FOO, 54} and {BAR, "hello"}. This is classic use case of an union:
unfortunately, unions don't handle constructors very well, so std::string wont work very well inside union (unless they changed it recently :-). But there's another way to implement an union:
NULL pointers are indicating that the value is not being used. (note that this Union class becomes a nightmare to maintain, if you need to add more alternative types to it)
Now the required struct looks like this:
Once you have this, making an array out of it is very trivial:
will be able to store values like {{ID_FOO,33}, {ID_BAR,"hello"}}