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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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:
Full Gist here: https://gist.github.com/nstansbury/6d627a447ca3b4ebbcf2c49ae37922c5