浏览代码

Fixing indexing bug in variant.
Adding <T> constructor.
Adding utility methods such as get<size_t>, std::get<size_t>, is<T>, and get_type_index<T>.

Samuel Jaffe 8 年之前
父节点
当前提交
c309194e34
共有 1 个文件被更改,包括 42 次插入4 次删除
  1. 42 4
      variant.hpp

+ 42 - 4
variant.hpp

@@ -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 */