While this isn't how C++ is supposed to be used, it isn't entirely impossible.
#include <string>
#include <map>
class MyClass {
public:
MyClass(const std::string& type, const std::string& name, const std::string& value);
private:
void parse(const std::string& type_, const std::string& name_, const std::string& value_);
template <typename T>
T* getDataMember(const std::string& name);
int my_int;
double my_double;
char my_char;
std::map<std::string, char*> members; //Map of strings to member memory locations
};
MyClass::MyClass(const std::string& type, const std::string& name, const std::string& value)
{
//List of members will have to be hardcoded
members["my_int"] = reinterpret_cast<char*>(&my_int);
members["my_double"] = reinterpret_cast<char*>(&my_double);
members["my_char"] = reinterpret_cast<char*>(&my_char);
this->parse(type, name, value);
}
template <typename T>
T* MyClass::getDataMember(const std::string& name) {
return reinterpret_cast<T*>(members[name]); //Will need to handle invalid names
}
void MyClass::parse(const std::string& type_, const std::string& name_, const std::string& value_)
{
if (type_=="int")
{
int* int_ = getDataMember<int>(name_);
(*int_)=atoi(value_.c_str());
}
}
int main(void) {
MyClass c("int","my_int","5");
return 0;
}
The idea is to keep a map
to reference string
s to member addresses. Accessing the map with the string
will return the address of the member corresponding to that string
. However, this map
will have to be hardcoded when new members are introduced to the class. Also, the getDataMember
function will have to handle cases where invalid names are passed into the class.
Inefficiencies
string
comparisons are fundamentally slow. The comparisons occur
when you are inserting members into the map
, when you are going
through your parse
function trying to identify the type, and when
you searching through the map for the correct key.
Possible ways to get rid of hardcoding
Suppose there is a way to fill the map without hardcoding. That would involve knowing what data members are present in the class. Since there does not seem to be such a functionality in C++, we would have to parse the file, or at least the part of the file that contains the class. However, we need this to be done before the file is compiled. This leaves us with 2 options:
- Do it at compile-time, which involves using preprocessor directives. Unfortunately, I have no idea of any way to utilize preprocessor directives to do so.
- Program an external executable that parses files in your project/workspace to identify the data members of the class and proceed to append the filling of the member map in the class's constructor(s). i.e. Automate the map filling process through an external executable. We can then ensure that this external executable is always run whenever the project is build through pre-build events.
Conclusion
I think it's best to either find another approach to the problem you are trying to solve, or use a whole other language because it seems C++ was not built for this.
Factoring in what your real problem is
I believe the solution you are looking for is called deserialization.
class MyClass {
public:
void Deserialize(XMLParser xml);
private:
int my_int;
double my_double;
char my_char;
};
void MyClass::Deserialize(XMLParser xml) {
while(xml.ReadLine() != "MEMBERS"); //Advances the XML parser to the line that specifies the members
//Proceed to deserialize the members in order
//This requires the file to list the members in the correct order
my_int = atoi(xml.ReadLine().c_str());
my_double = atof(xml.ReadLine().c_str());
my_char = atoi(xml.ReadLine().c_str());
}