diff options
-rw-r--r-- | glib/glibmm/value.h | 32 | ||||
-rw-r--r-- | glib/glibmm/value_custom.h | 40 | ||||
-rw-r--r-- | 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 9f663810..f2d3f309 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 9e42dd92..0284888c 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 47da4645..a824f948 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<> |