Reputation: 479
Have a very simple cpp code.
FileName: file.cpp
#include "file.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
int main()
{
Message_t msg;
memset(&msg,0,sizeof(Message_t));
msg.message_id = 1234;
strcpy(msg.message,"data");
Message_Descriptor_t desc ;
memset(&desc, 0, sizeof(Message_Descriptor_t));
desc.no_of_fields = 2;
desc.fields = malloc(2 * sizeof(Field_Descriptor_t));
strcpy(desc.fields[0].var_name, "message_id");
desc.fields[0].type = FIELD_INT;
strcpy(desc.fields[1].var_name, "message");
desc.fields[1].type = FIELD_CHAR;
char *json_string = "";
BUILD_MSG(msg,desc,json_string);
}
FileName: file.hpp
#ifndef _FILE_HPP_
#define _FILE_HPP_
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct Message_s
{
int message_id;
char *message;
} Message_t;
typedef enum
{
FIELD_INT = 0,
FIELD_CHAR = 1
} FieldType_e;
typedef struct Field_Descriptor_s
{
char *var_name;
FieldType_e type;
} Field_Descriptor_t;
typedef struct Message_Descriptor_s
{
int no_of_fields;
Field_Descriptor_t *fields;
} Message_Descriptor_t;
#define BUILD_STRING(key, value ,json_string) \
{ \
strcat(json_string, key); \
strcat(json_string, "|"); \
strcat(json_string, value. ## key); \
}
#define BUILD_INT(key, value ,json_string) \
{ \
strcat(json_string, key); \
strcat(json_string, "|"); \
char buffer [33]; \
strcat(json_string, key); \
}
#define BUILD_MSG(msg, msg_descriptor, json_string) \
{ \
for (int i=0; i < msg_descriptor.no_of_fields; i++) \
{ \
Field_Descriptor_t field = msg_descriptor.fields[i]; \
char *var_name = NULL; \
strcpy(var_name, field.var_name); \
switch(field.type) \
{ \
case FIELD_CHAR: \
BUILD_STRING(var_name, msg, json_string); \
break; \
case FIELD_INT: \
BUILD_INT(var_name, msg, json_string); \
break; \
default: \
break; \
} \
} \
}
#define BUILD_JSON_MSG (msg, msg_descriptor, json_string) \
{ \
BUILD_MSG(msg,msg_descriptor); \
}
#endif
Getting the following compilaton error:
g++ -c file.cpp
In file included from file.cpp:1:
file.cpp:25:1: error: pasting "." and "var_name" does not give a valid preprocessing token
file.cpp: In function 'int main()':
file.cpp:18: error: invalid conversion from 'void*' to 'Field_Descriptor_t*'
file.cpp:25: error: 'struct Message_t' has no member named 'var_name'
The logic with json_string is filled for dummy purpose in the above example.
How do we access the member variable of a structure by keeping in reference another descriptor structure, containing the member variable name stored.
Thanks in advance.
Upvotes: 0
Views: 225
Reputation: 5341
After a long chat, I've figured out what you're trying to do and was able to rewrite it in modern C++. This is what I came up with:
#include <string>
#include <vector>
#include <variant>
#include <iostream>
#include <unordered_map>
using Field_t = std::variant<int, std::string>;
using Message_t = std::unordered_map<std::string, Field_t>;
using Field_Descriptor_t = std::string;
using Message_Descriptor_t = std::vector<Field_Descriptor_t>;
struct Visitor {
std::string &json_string;
void operator()(const int value) {
json_string += std::to_string(value);
}
void operator()(const std::string &value) {
json_string += value;
}
};
void buildMsg(const Message_t &msg, const Message_Descriptor_t &desc, std::string &json_string) {
Visitor visitor{json_string};
for (const Field_Descriptor_t &field : desc) {
json_string += field;
json_string += '|';
std::visit(visitor, msg.at(field));
json_string += '\n';
}
}
int main() {
Message_t msg;
msg["message_id"] = 1234;
msg["message"] = "data";
Message_Descriptor_t desc;
desc.push_back("message_id");
desc.push_back("message");
std::string json_string;
buildMsg(msg, desc, json_string);
std::cout << json_string;
}
The output of this program is:
message_id|1234
message|data
Having Message_Descriptor_t
refer back to Message_t
doesn't really seem necessary to me. The only benefit it seems to add is order. The code can be simplified further, leaving almost no resemblance to the original code.
#include <string>
#include <vector>
#include <variant>
#include <iostream>
using Key = std::string;
using Value = std::variant<int, std::string>;
using Pair = std::pair<Key, Value>;
using Message = std::vector<Pair>;
struct Stringify {
std::string &output;
void operator()(const int value) {
output += std::to_string(value);
}
void operator()(const std::string &value) {
output += value;
}
};
void stringifyMessage(std::string &output, const Message &message) {
for (const Pair &pair : message) {
output += pair.first;
output += '|';
std::visit(Stringify{output}, pair.second);
output += '\n';
}
}
int main() {
Message message;
message.emplace_back("message_id", 1234);
message.emplace_back("message", "data");
std::string output;
stringifyMessage(output, message);
std::cout << output;
}
Compare this with the original C-like C++ code in the question and you'll see why I love C++ so much.
Upvotes: 1