[glibmm] Value: Only use RefPtr specialization for types that have get_base_type().



commit 0aa8c79f09e407087596158693f3a3098ad6aa5e
Author: Murray Cumming <murrayc murrayc com>
Date:   Sun Apr 9 12:25:59 2017 +0200

    Value: Only use RefPtr specialization for types that have get_base_type().
    
    For instance, RefPtr to ObjectBase-derived types, or other types that
    try to have a similar API.
    
    Previously, this assumed that any Value<RefPtr<T>> was for a T that had
    a get_base_type() (wrapping an underlying glib/gtk C type).

 glib/glibmm/value.h        |   32 +++++++++++++++++++++++++++++---
 glib/glibmm/value_custom.h |   40 ++++++++++++++++++++--------------------
 tests/glibmm_value/main.cc |   27 +++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 23 deletions(-)
---
diff --git a/glib/glibmm/value.h b/glib/glibmm/value.h
index 9f66381..f2d3f30 100644
--- a/glib/glibmm/value.h
+++ b/glib/glibmm/value.h
@@ -223,18 +223,42 @@ public:
 // More spec-compliant compilers (such as Tru64) need this to be near Glib::Object instead.
 #ifdef GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
 
+namespace Traits {
+
+template<typename, typename>
+struct HasGetBaseType;
+
+template<typename T, typename Ret, typename... Args>
+struct HasGetBaseType<T, Ret(Args...)> {
+  template<typename U, U>
+   struct Check;
+
+  template<typename U>
+  static std::true_type
+  Test(Check<Ret(*)(Args...), &U::get_base_type>*);
+
+  template<typename U>
+  static std::false_type Test(...);
+
+  static const bool value = decltype(Test<T>(0))::value;
+  //using type = decltype(Test<T>(0));
+};
+
+} // namespace Traits
+
 /** Partial specialization for RefPtr<> to Glib::Object.
  * @ingroup glibmmValue
  */
 template <class T>
-class Value<Glib::RefPtr<T>> : public ValueBase_Object
+class Value<Glib::RefPtr<T>, typename std::enable_if<Glib::Traits::HasGetBaseType<T, GType()>::value>::type>
+: public ValueBase_Object
 {
 public:
   using CppType = Glib::RefPtr<T>;
 
   static GType value_type() { return T::get_base_type(); }
 
-  void set(const CppType& data) { set_object(data.get()); }
+  void set(const CppType& data) { set_object(const_cast<std::remove_const_t<T>*>(data.get())); }
   CppType get() const { return std::dynamic_pointer_cast<T>(get_object_copy()); }
 };
 
@@ -244,8 +268,9 @@ public:
 /** Partial specialization for RefPtr<> to const Glib::Object.
  * @ingroup glibmmValue
  */
+/*
 template <class T>
-class Value<Glib::RefPtr<const T>> : public ValueBase_Object
+class Value<Glib::RefPtr<const T>, typename std::enable_if<std::is_base_of<Glib::ObjectBase, 
T>::value>::type> : public ValueBase_Object
 {
 public:
   using CppType = Glib::RefPtr<const T>;
@@ -255,6 +280,7 @@ public:
   void set(const CppType& data) { set_object(const_cast<T*>(data.get())); }
   CppType get() const { return std::dynamic_pointer_cast<T>(get_object_copy()); }
 };
+*/
 #endif // GLIBMM_HAVE_DISAMBIGUOUS_CONST_TEMPLATE_SPECIALIZATIONS
 
 #endif // GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
diff --git a/glib/glibmm/value_custom.h b/glib/glibmm/value_custom.h
index 9e42dd9..0284888 100644
--- a/glib/glibmm/value_custom.h
+++ b/glib/glibmm/value_custom.h
@@ -96,7 +96,7 @@ private:
  * cannot ensure that no exceptions will be thrown, consider using either
  * a normal pointer or a smart pointer to hold your objects indirectly.
  */
-template <class T>
+template <class T, typename Enable = void>
 class Value : public ValueBase_Boxed
 {
 public:
@@ -120,8 +120,8 @@ private:
  * No attempt is made to manage the memory associated with the
  * pointer, you must take care of that yourself.
  */
-template <class T>
-class Value<T*> : public Value_Pointer<T*>
+template <class T, typename Enable>
+class Value<T*, Enable> : public Value_Pointer<T*>
 {
 };
 
@@ -130,8 +130,8 @@ class Value<T*> : public Value_Pointer<T*>
  * No attempt is made to manage the memory associated with the
  * pointer, you must take care of that yourself.
  */
-template <class T>
-class Value<const T*> : public Value_Pointer<const T*>
+template <class T, typename Enable>
+class Value<const T*, Enable> : public Value_Pointer<const T*>
 {
 };
 
@@ -225,29 +225,29 @@ Value_Pointer<PtrT>::get() const
 /**** Glib::Value<T> *******************************************************/
 
 // Static data, specific to each template instantiation.
-template <class T>
-GType Value<T>::custom_type_ = 0;
+template <class T, typename Enable>
+GType Value<T, Enable>::custom_type_ = 0;
 
-template <class T>
+template <class T, typename Enable>
 inline void
-Value<T>::set(const typename Value<T>::CppType& data)
+Value<T, Enable>::set(const typename Value<T, Enable>::CppType& data)
 {
   // Assume the value is already default-initialized.  See value_init_func().
   *static_cast<T*>(gobject_.data[0].v_pointer) = data;
 }
 
-template <class T>
-inline typename Value<T>::CppType
-Value<T>::get() const
+template <class T, typename Enable>
+inline typename Value<T, Enable>::CppType
+Value<T, Enable>::get() const
 {
   // Assume the pointer is not NULL.  See value_init_func().
   return *static_cast<T*>(gobject_.data[0].v_pointer);
 }
 
 // static
-template <class T>
+template <class T, typename Enable>
 GType
-Value<T>::value_type()
+Value<T, Enable>::value_type()
 {
   if (!custom_type_)
   {
@@ -258,26 +258,26 @@ Value<T>::value_type()
 }
 
 // static
-template <class T>
+template <class T, typename Enable>
 void
-Value<T>::value_init_func(GValue* value)
+Value<T, Enable>::value_init_func(GValue* value)
 {
   // Never store a NULL pointer (unless we're out of memory).
   value->data[0].v_pointer = new (std::nothrow) T();
 }
 
 // static
-template <class T>
+template <class T, typename Enable>
 void
-Value<T>::value_free_func(GValue* value)
+Value<T, Enable>::value_free_func(GValue* value)
 {
   delete static_cast<T*>(value->data[0].v_pointer);
 }
 
 // static
-template <class T>
+template <class T, typename Enable>
 void
-Value<T>::value_copy_func(const GValue* src_value, GValue* dest_value)
+Value<T, Enable>::value_copy_func(const GValue* src_value, GValue* dest_value)
 {
   // Assume the source is not NULL.  See value_init_func().
   const T& source = *static_cast<T*>(src_value->data[0].v_pointer);
diff --git a/tests/glibmm_value/main.cc b/tests/glibmm_value/main.cc
index 47da464..a824f94 100644
--- a/tests/glibmm_value/main.cc
+++ b/tests/glibmm_value/main.cc
@@ -78,6 +78,10 @@ test()
 
   Glib::init();
 
+  // TODO: Put this test, of internal stuff, somewhere else.
+  static_assert(Glib::Traits::HasGetBaseType<DerivedObject, GType()>::value,
+    "DerivedObject has no get_base_type().");
+
   // RefPtr to Glib::ObjectBase-derived type:
   {
     GObject* gobject = G_OBJECT(g_object_new(TEST_TYPE_DERIVED, nullptr));
@@ -114,6 +118,29 @@ test()
     const auto v = value.get();
     assert(v);
   }
+
+  {
+    auto foo = std::make_shared<Foo>();
+
+    // custom pointer
+    Glib::Value<std::shared_ptr<Foo>> value;
+    value.init(Glib::Value<std::shared_ptr<Foo>>::value_type()); // TODO: Avoid this step?
+    value.set(foo);
+
+    const auto v = value.get();
+    assert(v);
+  }
+
+  {
+    auto foo = std::make_shared<Foo>();
+
+    Glib::Value<std::shared_ptr<const Foo>> value;
+    value.init(Glib::Value<std::shared_ptr<const Foo>>::value_type()); // TODO: Avoid this step?
+    value.set(foo);
+
+    const auto v = value.get();
+    assert(v);
+  }
 }
 
 // Glib::Object RefPtr<>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]