Last active
August 1, 2024 08:18
-
-
Save Mr-Andersen/cd5f9d8740e03b3a779bd49da281652d to your computer and use it in GitHub Desktop.
Implementation of tagged union without typeinfo library. Beware: this code contains a dozen undefined behaviours and a dozen more. Use only as inspiration.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
// get_type<i, Ts...>::type -> Ts[i] (Compile error of i >= length(Ts)) | |
template<size_t i, typename T, typename... Ts> | |
struct get_type { | |
typedef typename get_type<i - 1, Ts...>::type type; | |
}; | |
template<typename T, typename... Ts> | |
struct get_type<0, T, Ts...> { | |
typedef T type; | |
}; | |
// Ts[index_type<A, Ts...>::value] == A (Compilation error if A not in Ts) | |
template<typename A, typename T, typename... Ts> | |
struct index_type { | |
static const size_t value = index_type<A, Ts...>::value + 1; | |
}; | |
template<typename A, typename... Ts> | |
struct index_type<A, A, Ts...> { | |
static const size_t value = 0; | |
}; | |
template<typename T> | |
constexpr T max(const T& a, const T& b) { | |
return a > b ? a : b; | |
} | |
// max_size<Ts...>::value | |
template<typename T, typename... Ts> | |
struct max_size { | |
static const size_t value = max(sizeof(T), max_size<Ts...>::value); | |
}; | |
template<typename T> | |
struct max_size<T> { | |
static const size_t value = sizeof(T); | |
}; | |
template<typename... Ts> | |
class Variant { | |
size_t curr_type; | |
char data[max_size<Ts...>::value]; | |
public: | |
Variant(): | |
curr_type(), | |
data() {} | |
template<typename T> | |
Variant(const T& x): | |
curr_type(index_type<T, Ts...>::value) | |
{ | |
auto ptr = reinterpret_cast<const char*>(&x); | |
std::copy(ptr, ptr + sizeof(T), this->data); | |
} | |
template<typename T> | |
const T& operator=(const T& x) { | |
this->curr_type = index_type<T, Ts...>::value; | |
auto ptr = reinterpret_cast<const char*>(&x); | |
std::copy(ptr, ptr + sizeof(T), this->data); | |
return x; | |
} | |
template<typename T> | |
bool is() const { | |
return this->curr_type == index_type<T, Ts...>::value; | |
} | |
template<typename T> | |
T& as() { | |
if (!this->is<T>()) | |
throw std::runtime_error("Requested type is not contained"); | |
return *reinterpret_cast<T*>(this->data); | |
} | |
template<typename T> | |
bool into(T& x) { | |
if (!this->is<T>()) | |
return false; | |
x = *reinterpret_cast<T*>(this->data); | |
return true; | |
} | |
}; | |
int main() { | |
Variant<short unsigned int, long int [3]> v; | |
v = (long int [3]) {10, -123, 345}; | |
if (v.is<long int [3]>()) { | |
std::cout << v.as<long int [3]>()[0] << std::endl; | |
} | |
} |
I agree, this Gist was very helpful in me solving an identical problem I had in passing sensor data around on an RP2040/Arduino platform.
I never full understood the templating language you used, but it inspired me to work on a slightly different templated approach for a variant KeyValue pair propery set:
PropertySet props = PropertySet();
// Set the property key/value pair
props.setProperty("IntProp", 12345);
props.setProperty("StrProp", std::string("A string property"));
props.setProperty("ArrProp", std::array<int, 5>({1,2,3,4,5}));
// Get the property values based on the key
auto intProp = props.getProperty<int>("IntProp");
auto strProp = props.getProperty<std::string>("StrProp");
auto arrProp = props.getProperty<std::array<int, 5>>("ArrProp");
// Get the underlying Property descriptor
PropertyType::shared_ptr propType = props.getPropertyType("IntProp");
if(propType->typeOf<int>()){
std::shared_ptr<PropertyDescriptor<int>> propertyDesc;
propertyDesc = propType->getDescriptor<int>();
Serial.print("\nIntProp Descriptor Value: ");
Serial.print(propertyDesc->value());
}
Full Gist here: https://gist.github.com/nstansbury/6d627a447ca3b4ebbcf2c49ae37922c5
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
i don't think, that you should delete the gist.
It was helpful to me, because it is a simple (=short) and therefore understandable implementation of a variant type.
I think these comments (or a comment in the original source) are enough to document the possible problems with this code and the things a user of this might want to think about