I'm working with a library that uses a C interface and several functions that pass a pointer to a struct as the output (not return).
The struct is something like
struct S {
short a;
short b;
union {
char cdata[5];
short sdata[5];
long ldata[5];
float fdata[5];
double dfdata[5];
} u;
}
I've written some template classes that can provide access to this in the form
auto parameter = MyClass<double>(constructor parameters);
parameter.SetValue(5.2); // Sets u.dfdata[0] = 5.2;
// other functions for changing index, or passing in a vector, etc
This is nice(ish) in that it abstracts away a lot of the required knowledge about structs, and only requires the user (still me, but whatever...) to know about the type of the parameter (double, float, long, short or char).
However, it's a compile time construct. The hardware I'm communicating with through this library is able to provide a function that has something like:
// renamed and tidied for ease of reading
// I don't have the source for this function, only docs
short GetParameter(short address, short* prevAddress, short* nextAddress,
S* parameter, Other* info);
where info can be parsed to tell me the type of the parameter. This would, if it were not compile time and different types, allow something like
std::vector<??> a;
a.push_back(MyClass<double>(args));
a.push_back(MyClass<short>(args));
where double and short can be read from the info struct as a short (0 = char, 1 = short...) and the other arguments can be read from the S struct.
I can build a std::vector<std::variant<MyClass<char>, MyClass<short>, ..., MyClass<double>>> but then trying to work out how to use a variant has left me confused if this is a good idea at all.
I want to be able to store sets of different types of parameters, for example for saving a complete configuration, but at the moment I think my functions are all compile-time calculations (variations on if constexpr(std::is_same_v<T, char>) { // do something with u.cdata[index] }).
If I want to be able to create lists with a single type, I can't (as far as I can work out) have virtual T ReadValue() or virtual void SetValue(T) because I can't use templating on virtual functions, and if I template the class (as I do now) then I have different (class) types which become hard to operate on.
An ideal solution would look something like
using valType = std::variant<char, short, long, float, double>;
using varType = std::variant<MyClass<char>, ..., MyClass<double>>;
// Read this from some file, or whatever
auto values = std::vector<valType> { 3, 2.6f, 17.2, 1523l };
std::vector<varType> paramList = MyFunctionThatReadsThroughParamToNextParam();
for (size_t i = 0; i < values.size(); i++) {
paramList[i].SetValue(values[i]);
// where the type contained in values[i] matches the type expected by paramList[i]
// ideally this would throw if the types were incorrect, but really
// any defined behaviour here would be great.
}
Is anything like this remotely possible?