My preferred methodology is to simply return a Map from the function with pointers to the members... (it's not automatic, and it doesn't use any preprocessor magic, but it's simple and easy to read)
This may not work in some situations where a pointer to the value is no sufficient, but I prefer it over getters and setters.
Here's an example from a program I wrote
struct LogThemeSettings {
static constexpr char FOREGROUND[] = "foreground";
static constexpr char BACKGROUND[] = "background";
static constexpr char ITALIC[] = "italic";
static constexpr char BOLD[] = "bold";
static constexpr char WEIGHT[] = "weight";
static constexpr char UNDERLINE[] = "underline";
static constexpr char CAPITALIZATION[] = "capitalization";
static constexpr char TRUE[] = "true";
static constexpr char FALSE[] = "false";
static std::set<QString> VALID_THEME_ATTRIBUTES;
std::map<QString, QString> NamedEntity1;
std::map<QString, QString> NamedEntity2;
std::map<QString, QString> NamedEntity3;
std::map<QString, QString> NamedEntity4;
std::map<QString, QString> NamedEntity5;
std::map<QString, QString> NamedEntity6;
std::map<QString, QString> NamedEntity7;
std::map<QString, QString> NamedEntity8;
std::map<QString, QString> NamedKey;
std::map<QString, QString> NamedValue;
std::map<QString, QString> VariableName;
std::map<QString, QString> VariableValue;
std::map<QString, QString> QuotedString;
std::map<QString, QString> LevelError;
std::map<QString, QString> LevelWarning;
std::map<QString, QString> LevelLog;
std::map<QString, QString> Good;
std::map<QString, QString> Bad;
std::map<QString, QString> Uri;
std::map<QString, QString> ClassType;
std::map<QString, QString> Category;
std::map<QString, QString> Time;
std::map<QString, QString> Address;
std::map<QString, QString> Numeric;
std::map<QString, QString> Path;
std::map<QString, QString> Directory;
std::map<QString, QString> Foreground;
std::map<QString, QString> Background;
std::map<QString, QString> Cursor;
/**
* We want the vast majority of code to access these struct members directly.
* In a couple places (like the UI) that is cubmersome though. This map allows the members
* of the theme to be accessed by name, and changed via pointer.
*/
std::map<QString, std::map<QString, QString>*> getMap() {
return std::map<QString, std::map<QString, QString>*> {
{"NamedEntity1", &NamedEntity1},
{"NamedEntity2", &NamedEntity2},
{"NamedEntity3", &NamedEntity3},
{"NamedEntity4", &NamedEntity4},
{"NamedEntity5", &NamedEntity5},
{"NamedEntity6", &NamedEntity6},
{"NamedEntity7", &NamedEntity7},
{"NamedEntity8", &NamedEntity8},
{"NamedKey", &NamedKey},
{"NamedValue", &NamedValue},
{"VariableName", &VariableName},
{"VariableValue", &VariableValue},
{"QuotedString", &QuotedString},
{"LevelError", &LevelError},
{"LevelWarning", &LevelWarning},
{"LevelLog", &LevelLog},
{"Good", &Good},
{"Bad", &Bad},
{"Uri", &Uri},
{"ClassType", &ClassType},
{"Category", &Category},
{"Time", &Time},
{"Address", &Address},
{"Numeric", &Numeric},
{"Path", &Path},
{"Directory", &Directory},
{"Foreground", &Foreground},
{"Background", &Background},
{"Cursor", &Cursor},
};
}
// now that we can access the members via iterator it's easy to implement this
// `isValid()` function to check that all members have values.
bool isValid() {
auto members = getMap();
for(std::map<QString, std::map<QString, QString>*>::iterator it = members.begin(); it != members.end(); ++it) {
if(it->second->empty()) {
return false;
}
}
return true;
}
typedef struct T { } type;
form. This is not ancient C.struct T { };
is all you need to do. – Ferroelectric