|
|
@@ -81,6 +81,7 @@ template<> struct variant_helper<> {
|
|
|
template <typename... Ts>
|
|
|
struct variant {
|
|
|
private:
|
|
|
+ static const constexpr size_t num_types = sizeof...(Ts);
|
|
|
static const constexpr size_t data_size = static_max<sizeof(Ts)...>::value;
|
|
|
static const constexpr size_t data_align = static_max<alignof(Ts)...>::value;
|
|
|
|
|
|
@@ -92,11 +93,24 @@ private:
|
|
|
return 0xFFFFFFFF;
|
|
|
}
|
|
|
|
|
|
+ template <typename T>
|
|
|
+ static inline size_t get_type_index() {
|
|
|
+ return num_types - type_index<T, Ts...>::value - 1;
|
|
|
+ }
|
|
|
+
|
|
|
size_t type_id;
|
|
|
data_t data;
|
|
|
public:
|
|
|
+ template <size_t I>
|
|
|
+ using at = typename std::tuple_element<I, std::tuple<Ts...>>::type;
|
|
|
+
|
|
|
variant() : type_id(invalid_type()), data() { }
|
|
|
|
|
|
+ template <typename T>
|
|
|
+ variant(T const & value) : type_id(invalid_type()), data() {
|
|
|
+ set<T>(value);
|
|
|
+ }
|
|
|
+
|
|
|
variant(const variant<Ts...>& old) : type_id(old.type_id), data()
|
|
|
{
|
|
|
helper_t::copy(old.type_id, &old.data, &data);
|
|
|
@@ -118,7 +132,7 @@ public:
|
|
|
|
|
|
template<typename T>
|
|
|
inline bool is() const {
|
|
|
- return (type_id == type_index<T, Ts...>::value);
|
|
|
+ return (type_id == get_type_index<T>());
|
|
|
}
|
|
|
|
|
|
inline bool valid() const {
|
|
|
@@ -131,14 +145,14 @@ public:
|
|
|
// First we destroy the current contents
|
|
|
helper_t::destroy(type_id, &data);
|
|
|
new (&data) T(std::forward<Args>(args)...);
|
|
|
- type_id = type_index<T, Ts...>::value;
|
|
|
+ type_id = get_type_index<T>();
|
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
|
T& get()
|
|
|
{
|
|
|
// It is a dynamic_cast-like behaviour
|
|
|
- if (type_id == type_index<T, Ts...>::value)
|
|
|
+ if (is<T>())
|
|
|
return *reinterpret_cast<T*>(&data);
|
|
|
else
|
|
|
throw std::bad_cast();
|
|
|
@@ -148,15 +162,39 @@ public:
|
|
|
T const& get() const
|
|
|
{
|
|
|
// It is a dynamic_cast-like behaviour
|
|
|
- if (type_id == type_index<T, Ts...>::value)
|
|
|
+ if (is<T>())
|
|
|
return *reinterpret_cast<T const*>(&data);
|
|
|
else
|
|
|
throw std::bad_cast();
|
|
|
}
|
|
|
|
|
|
+ size_t index() const { return type_id; }
|
|
|
+
|
|
|
+ template <size_t I>
|
|
|
+ auto get() const -> at<I> const & {
|
|
|
+ return get<at<I>>();
|
|
|
+ }
|
|
|
+
|
|
|
+ template <size_t I>
|
|
|
+ auto get() -> at<I> & {
|
|
|
+ return get<at<I>>();
|
|
|
+ }
|
|
|
+
|
|
|
~variant() {
|
|
|
helper_t::destroy(type_id, &data);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+namespace std {
|
|
|
+ template <size_t I, typename... Ts>
|
|
|
+ auto get(variant<Ts...> const & var) -> typename variant<Ts...>::template at<I> const & {
|
|
|
+ return var.template get<I>();
|
|
|
+ }
|
|
|
+
|
|
|
+ template <size_t I, typename... Ts>
|
|
|
+ auto get(variant<Ts...> & var) -> typename variant<Ts...>::template at<I> & {
|
|
|
+ return var.template get<I>();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#endif /* variant_h */
|