Browse Source

Rework pointer definition and data struct members

Michael Ragazzon 4 years ago
parent
commit
c09da72495

+ 180 - 51
Include/RmlUi/Core/DataTypeRegister.h

@@ -43,7 +43,7 @@ namespace Rml {
 #define RMLUI_LOG_TYPE_ERROR_ASSERT(T, val, msg) RMLUI_ASSERTMSG(val, (String(msg) + String(" T: ") + String(rmlui_type_name<T>())).c_str())
 
 template<typename T>
-struct is_valid_data_scalar {
+struct is_builtin_data_scalar {
 	static constexpr bool value = std::is_arithmetic<T>::value
 		|| std::is_same<typename std::remove_cv<T>::type, String>::value;
 };
@@ -54,29 +54,82 @@ class StructHandle {
 public:
 	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {}
 
-	// Register a member object. Any data type can be used.
+	/// Register a member object or member getter function.
+	/// @note Underlying type must be registered before it is used as a member.
+	/// @note Getter functions can return by reference, raw pointer, or by value. If returned by value,
+	///       the returned type must be a scalar data type, otherwise any data type can be used.
+	/// @example
+	///		struct Invader {
+	///			int health;
+	///			std::vector<Weapon>& GetWeapons();
+	///			/* ... */
+	/// 	};
+	///		struct_handle.RegisterMember("health", &Invader::health);
+	///		struct_handle.RegisterMember("weapons", &Invader::GetWeapons);
 	template <typename MemberType>
-	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr);
-
-	// Register a member using a getter function. Must return value by reference or by raw pointer. Any data type can be used.
-    template<typename ReturnType>
-    StructHandle<Object>& RegisterMember(const String& name, ReturnType(Object::* member_get_func_ptr)());
+	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr) {
+		RegisterMemberDetail(name, member_ptr);
+		return *this;
+	}
 
-	// Register a member using a getter function and optionally a setter function. Only scalar data types can be used.
-	// Can get and set by value or by reference.
+	/// Register member getter and setter functions. The getter and setter functions must return and assign scalar value types.
+	/// @note Underlying type must be registered before it is used as a member.
+	/// @note Getter and setter functions can return by reference, raw pointer, or by value. Only scalar data types allowed.
 	/// @example
-	///     RegisterMemberScalar("color", &Invader::GetColor, &Invader::SetColor);
-	///       where functions can be declared as 
-	///     MyColorType Invader::GetColor();
-	///     void Invader::SetColor(MyColorType color);
-	template<typename ReturnType = std::nullptr_t, typename AssignType = std::nullptr_t>
-	StructHandle<Object>& RegisterMemberScalar(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType) = nullptr);
+	///		struct Invader {
+	///			MyColorType GetColor() const;
+	///			void SetColor(MyColorType color);
+	///			/* ... */
+	/// 	};
+	///		struct_handle.RegisterMember("color", &Invader::GetColor, &Invader::SetColor);
+	template <typename MemberGetType, typename MemberSetType>
+	StructHandle<Object>& RegisterMember(const String& name, MemberGetType Object::* member_get_func_ptr, MemberSetType Object::* member_set_func_ptr) {
+		RegisterMemberDetail(name, member_get_func_ptr, member_set_func_ptr);
+		return *this;
+	}
 
 	explicit operator bool() const {
 		return type_register && struct_definition;
 	}
 
 private:
+
+	template <typename MemberType>
+	bool RegisterMemberDetail(const String& name, MemberType Object::* member_object_ptr);
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType& (Object::* member_get_func_ptr)());
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType& (Object::* member_get_func_ptr)() const);
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType* (Object::* member_get_func_ptr)());
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType* (Object::* member_get_func_ptr)() const);
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)());
+
+	template <typename ReturnType>
+	bool RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)() const);
+
+	template <typename ReturnType, typename AssignType>
+	bool RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType));
+
+	template <typename ReturnType, typename AssignType>
+	bool RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)() const, void(Object::* member_set_func_ptr)(AssignType));
+
+	template<typename MemberType>
+	bool CreateMemberObjectDefinition(const String& name, MemberType Object::* member_ptr);
+
+	template<typename BasicReturnType, typename MemberType>
+	bool CreateMemberGetFuncDefinition(const String& name, MemberType Object::* member_get_func_ptr);
+
+	template<typename UnderlyingType, typename MemberGetType, typename MemberSetType>
+	bool CreateMemberScalarGetSetFuncDefinition(const String& name, MemberGetType Object::* member_get_func_ptr, MemberSetType Object::* member_set_func_ptr);
+
 	DataTypeRegister* type_register;
 	StructDefinition* struct_definition;
 };
@@ -145,7 +198,7 @@ public:
 	template<typename T>
 	bool RegisterScalar(DataTypeGetFunc<T> get_func, DataTypeSetFunc<T> set_func)
 	{
-		static_assert(!is_valid_data_scalar<T>::value, "Cannot register scalar data type function. Arithmetic types and String are handled internally and does not need to be registered.");
+		static_assert(!is_builtin_data_scalar<T>::value, "Cannot register scalar data type function. Arithmetic types and String are handled internally and does not need to be registered.");
 		FamilyId id = Family<T>::Id();
 
 		auto scalar_func_definition = MakeUnique<ScalarFuncDefinition<T>>(get_func, set_func);
@@ -174,7 +227,7 @@ private:
 
 	// Get definition for scalar types that can be assigned to and from Rml::Variant.
 	// We automatically register these when needed, so users don't have to register trivial types manually.
-	template<typename T, typename std::enable_if<!PointerTraits<T>::is_pointer::value&& is_valid_data_scalar<T>::value, int>::type = 0>
+	template<typename T, typename std::enable_if<!PointerTraits<T>::is_pointer::value && is_builtin_data_scalar<T>::value, int>::type = 0>
 	VariableDefinition* GetDefinitionDetail()
 	{
 		FamilyId id = Family<T>::Id();
@@ -189,9 +242,9 @@ private:
 		return definition.get();
 	}
 
-	// Get definition for non-scalar types.
+	// Get definition for types that are not a built-in scalar.
 	// These must already have been registered by the user.
-	template<typename T, typename std::enable_if<!PointerTraits<T>::is_pointer::value && !is_valid_data_scalar<T>::value, int>::type = 0>
+	template<typename T, typename std::enable_if<!PointerTraits<T>::is_pointer::value && !is_builtin_data_scalar<T>::value, int>::type = 0>
 	VariableDefinition* GetDefinitionDetail()
 	{
 		FamilyId id = Family<T>::Id();
@@ -240,63 +293,139 @@ private:
 	TransformFuncRegister transform_register;
 };
 
+
+
+template <typename Object>
+template <typename MemberType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, MemberType Object::* member_object_ptr)
+{
+	return CreateMemberObjectDefinition(name, member_object_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType& (Object::* member_get_func_ptr)())
+{
+	return CreateMemberGetFuncDefinition<ReturnType>(name, member_get_func_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType& (Object::* member_get_func_ptr)() const)
+{
+	return CreateMemberGetFuncDefinition<ReturnType>(name, member_get_func_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType* (Object::* member_get_func_ptr)())
+{
+	return CreateMemberGetFuncDefinition<ReturnType>(name, member_get_func_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType* (Object::* member_get_func_ptr)() const)
+{
+	return CreateMemberGetFuncDefinition<ReturnType>(name, member_get_func_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)())
+{
+	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
+	using SetType = std::nullptr_t Object::*;
+	return CreateMemberScalarGetSetFuncDefinition<BasicReturnType>(name, member_get_func_ptr, SetType{});
+}
+
+
+template <typename Object>
+template <typename ReturnType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)() const)
+{
+	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
+	using SetType = std::nullptr_t Object::*;
+	return CreateMemberScalarGetSetFuncDefinition<BasicReturnType>(name, member_get_func_ptr, SetType{});
+}
+
+template <typename Object>
+template <typename ReturnType, typename AssignType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType))
+{
+	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
+	using BasicAssignType = typename std::remove_cv<typename std::remove_reference<AssignType>::type>::type;
+	using UnderlyingType = typename std::conditional<std::is_null_pointer<BasicReturnType>::value, BasicAssignType, BasicReturnType>::type;
+
+	static_assert(std::is_null_pointer<ReturnType>::value || std::is_null_pointer<AssignType>::value || std::is_same<BasicReturnType, BasicAssignType>::value, "Provided getter and setter functions must get and set the same type.");
+
+	return CreateMemberScalarGetSetFuncDefinition<UnderlyingType>(name, member_get_func_ptr, member_set_func_ptr);
+}
+
+template <typename Object>
+template <typename ReturnType, typename AssignType>
+bool StructHandle<Object>::RegisterMemberDetail(const String& name, ReturnType(Object::* member_get_func_ptr)() const, void(Object::* member_set_func_ptr)(AssignType))
+{
+	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
+	using BasicAssignType = typename std::remove_cv<typename std::remove_reference<AssignType>::type>::type;
+	using UnderlyingType = typename std::conditional<std::is_null_pointer<BasicReturnType>::value, BasicAssignType, BasicReturnType>::type;
+
+	static_assert(std::is_null_pointer<ReturnType>::value || std::is_null_pointer<AssignType>::value || std::is_same<BasicReturnType, BasicAssignType>::value, "Provided getter and setter functions must get and set the same type.");
+
+	return CreateMemberScalarGetSetFuncDefinition<UnderlyingType>(name, member_get_func_ptr, member_set_func_ptr);
+}
+
 template<typename Object>
 template<typename MemberType>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr)
+bool StructHandle<Object>::CreateMemberObjectDefinition(const String& name, MemberType Object::* member_ptr)
 {
-	if (VariableDefinition* member_definition = type_register->GetDefinition<MemberType>())
-	{
-		struct_definition->AddMember(
-			name,
-			MakeUnique<MemberObjectPointerDefinition<Object, MemberType>>(member_definition, member_ptr)
-		);
-	}
-	return *this;
+	VariableDefinition* underlying_definition = type_register->GetDefinition<MemberType>();
+	if (!underlying_definition)
+		return false;
+	struct_definition->AddMember(
+		name,
+		MakeUnique<MemberObjectDefinition<Object, MemberType>>(underlying_definition, member_ptr)
+	);
+	return true;
 }
 
 template<typename Object>
-template<typename ReturnType>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, ReturnType(Object::*member_get_func_ptr)())
+template<typename BasicReturnType, typename MemberType>
+bool StructHandle<Object>::CreateMemberGetFuncDefinition(const String& name, MemberType Object::* member_get_func_ptr)
 {
-	using BasicReturnType = typename std::remove_pointer<typename std::remove_reference<ReturnType>::type>::type;
-	static_assert(!std::is_same<ReturnType, BasicReturnType>::value, "Struct member getter function must return value by reference or raw pointer.");
-
 	VariableDefinition* underlying_definition = type_register->GetDefinition<BasicReturnType>();
+	if (!underlying_definition)
+		return false;
+
 	struct_definition->AddMember(
 		name,
-		MakeUnique<MemberFunctionPointerDefinition<Object, ReturnType, BasicReturnType>>(underlying_definition, member_get_func_ptr)
+		MakeUnique<MemberGetFuncDefinition<Object, MemberType, BasicReturnType>>(underlying_definition, member_get_func_ptr)
 	);
-	return *this;
+	return true;
 }
 
 template<typename Object>
-template<typename ReturnType, typename AssignType>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMemberScalar(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType))
+template<typename UnderlyingType, typename MemberGetType, typename MemberSetType>
+bool StructHandle<Object>::CreateMemberScalarGetSetFuncDefinition(const String& name, MemberGetType Object::* member_get_func_ptr, MemberSetType Object::* member_set_func_ptr)
 {
-	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
-	using BasicAssignType = typename std::remove_cv<typename std::remove_reference<AssignType>::type>::type;
-	using UnderlyingType = typename std::conditional<std::is_null_pointer<BasicReturnType>::value, BasicAssignType, BasicReturnType>::type;
-
-	static_assert(std::is_null_pointer<ReturnType>::value || std::is_null_pointer<AssignType>::value || std::is_same<BasicReturnType, BasicAssignType>::value, "Provided getter and setter functions must get and set the same type.");
-	static_assert(std::is_copy_assignable<UnderlyingType>::value, "Struct member getter and setter functions must return/assign a type that is copy assignable.");
-	static_assert(std::is_default_constructible<UnderlyingType>::value, "Struct member getter and setter functions must return/assign a type that is default constructible.");
+	static_assert(std::is_copy_assignable<UnderlyingType>::value, "Struct member getter/setter functions must return/assign a type that is copy assignable.");
+	static_assert(std::is_default_constructible<UnderlyingType>::value, "Struct member getter/setter functions must return/assign a type that is default constructible.");
 
 	VariableDefinition* underlying_definition = type_register->GetDefinition<UnderlyingType>();
 	if (!underlying_definition)
-		return *this;
+		return false;
 
-	DataVariableType type = underlying_definition->Type();
-	if (!(type == DataVariableType::Scalar || type == DataVariableType::Function))
+	if (underlying_definition->Type() != DataVariableType::Scalar)
 	{
-		RMLUI_LOG_TYPE_ERROR(UnderlyingType, "A getter/setter member function must return and assign a scalar data variable type.");
-		return *this;
+		RMLUI_LOG_TYPE_ERROR(UnderlyingType, "Non-scalar data variable member registered, but only scalar data variables are allowed here: A getter function returning by value, or a getter/setter function pair.");
+		return false;
 	}
 
 	struct_definition->AddMember(
 		name,
-		MakeUnique<MemberScalarFunctionPointerDefinition<Object, ReturnType, AssignType, UnderlyingType>>(underlying_definition, member_get_func_ptr, member_set_func_ptr)
+		MakeUnique<MemberScalarGetSetFuncDefinition<Object, MemberGetType, MemberSetType, UnderlyingType>>(underlying_definition, member_get_func_ptr, member_set_func_ptr)
 	);
-	return *this;
+	return true;
 }
 
 } // namespace Rml

+ 72 - 118
Include/RmlUi/Core/DataVariable.h

@@ -38,7 +38,7 @@
 
 namespace Rml {
 
-enum class DataVariableType { Scalar, Array, Struct, Function, MemberFunction };
+enum class DataVariableType { Scalar, Array, Struct };
 
 
 /*
@@ -112,8 +112,7 @@ public:
 
 class FuncDefinition final : public VariableDefinition {
 public:
-
-	FuncDefinition(DataGetFunc get, DataSetFunc set) : VariableDefinition(DataVariableType::Function), get(std::move(get)), set(std::move(set)) {}
+	FuncDefinition(DataGetFunc get, DataSetFunc set) : VariableDefinition(DataVariableType::Scalar), get(std::move(get)), set(std::move(set)) {}
 
 	bool Get(void* /*ptr*/, Variant& variant) override
 	{
@@ -137,8 +136,7 @@ private:
 template<typename T>
 class ScalarFuncDefinition final : public VariableDefinition {
 public:
-
-	ScalarFuncDefinition(DataTypeGetFunc<T> get, DataTypeSetFunc<T> set) : VariableDefinition(DataVariableType::Function), get(get), set(set) {}
+	ScalarFuncDefinition(DataTypeGetFunc<T> get, DataTypeSetFunc<T> set) : VariableDefinition(DataVariableType::Scalar), get(get), set(set) {}
 
 	bool Get(void* ptr, Variant& variant) override
 	{
@@ -195,50 +193,50 @@ private:
 	VariableDefinition* underlying_definition;
 };
 
-
-template<typename T>
-class PointerDefinition final : public VariableDefinition {
+class BasePointerDefinition : public VariableDefinition {
 public:
-	PointerDefinition(VariableDefinition* underlying_definition) : VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition) {}
+	BasePointerDefinition(VariableDefinition* underlying_definition) : VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition) {}
 
-	bool Get(void* ptr, Variant& variant) override
-	{
-		return underlying_definition->Get(DereferencePointer(ptr), variant);
-	}
-	bool Set(void* ptr, const Variant& variant) override
-	{
-		return SetDetail<T>(ptr, variant);
-	}
-	int Size(void* ptr) override
-	{
-		return underlying_definition->Size(DereferencePointer(ptr));
-	}
-	DataVariable Child(void* ptr, const DataAddressEntry& address) override
-	{
-		// TODO: Return the constness of T?
-		return underlying_definition->Child(DereferencePointer(ptr), address);
-	}
+	bool Get(void* ptr, Variant& variant) override;
+	bool Set(void* ptr, const Variant& variant) override;
+	int Size(void* ptr) override;
+	DataVariable Child(void* ptr, const DataAddressEntry& address) override;
+
+protected:
+	virtual void* DereferencePointer(void* ptr) = 0;
 
 private:
-	template<typename U, typename std::enable_if<!std::is_const<typename PointerTraits<U>::element_type>::value, int>::type = 0>
-	bool SetDetail(void* ptr, const Variant& variant)
-	{
-		return underlying_definition->Set(DereferencePointer(ptr), variant);
-	}
-	template<typename U, typename std::enable_if<std::is_const<typename PointerTraits<U>::element_type>::value, int>::type = 0>
-	bool SetDetail(void* /*ptr*/, const Variant& /*variant*/)
-	{
-		return false;
-	}
+	VariableDefinition* underlying_definition;
+};
+
+template<typename T>
+class PointerDefinition final : public BasePointerDefinition {
+public:
+	PointerDefinition(VariableDefinition* underlying_definition) : BasePointerDefinition(underlying_definition) {}
 
-	static void* DereferencePointer(void* ptr)
+protected:
+	void* DereferencePointer(void* ptr) override
 	{
 		return PointerTraits<T>::Dereference(ptr);
 	}
-
-	VariableDefinition* underlying_definition;
 };
 
+//template<typename T>
+//class ConstPointerDefinition final : public BasePointerDefinition {
+//public:
+//	ConstPointerDefinition(VariableDefinition* underlying_definition) : BasePointerDefinition(underlying_definition) {}
+//
+//	bool Set(void* ptr, const Variant& variant) override
+//	{
+//		// Emit warning
+//		return false;
+//	}
+//	DataVariable Child(void* ptr, const DataAddressEntry& address) override
+//	{
+//		// TODO: Return the constness of T?
+//		return PointerDefinition::Child(ptr, address);
+//	}
+//};
 
 class StructDefinition final : public VariableDefinition {
 public:
@@ -279,81 +277,39 @@ private:
 };
 
 
-template <typename Object, typename MemberType>
-class MemberAccessor {
-protected:
-	MemberAccessor(MemberType Object::* member_ptr) : member_ptr(member_ptr) {}
-
-	void* ResolvePointer(void* base_ptr) const {
-		return &(static_cast<Object*>(base_ptr)->*member_ptr);
-	}
-
-private:
-	MemberType Object::* member_ptr;
-};
 
-template <typename Object, typename MemberType>
-class MemberObjectPointerDefinition final : public VariableDefinition, public MemberAccessor<Object, MemberType> {
+template<typename Object, typename MemberType>
+class MemberObjectDefinition final : public BasePointerDefinition {
 public:
-	MemberObjectPointerDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_ptr)
-		: VariableDefinition(underlying_definition->Type()), MemberAccessor<Object, MemberType>(member_ptr), underlying_definition(underlying_definition) {}
+	MemberObjectDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_ptr) : BasePointerDefinition(underlying_definition), member_ptr(member_ptr) {}
 
-	bool Get(void* ptr, Variant& variant) override
-	{
-		return underlying_definition->Get(ResolvePointer(ptr), variant);
-	}
-	bool Set(void* ptr, const Variant& variant) override
-	{
-		return underlying_definition->Set(ResolvePointer(ptr), variant);
-	}
-	int Size(void* ptr) override
-	{
-		return underlying_definition->Size(ResolvePointer(ptr));
-	}
-	DataVariable Child(void* ptr, const DataAddressEntry& address) override
+protected:
+	void* DereferencePointer(void* base_ptr) override
 	{
-		return underlying_definition->Child(ResolvePointer(ptr), address);
+		return &(static_cast<Object*>(base_ptr)->*member_ptr);
 	}
-
 private:
-	using MemberAccessor<Object, MemberType>::ResolvePointer;
-
-	VariableDefinition* underlying_definition;
+	MemberType Object::* member_ptr;
 };
 
 
-template <typename Object, typename ReturnType, typename BasicReturnType>
-class MemberFunctionPointerDefinition final : public VariableDefinition {
+template<typename Object, typename MemberType, typename BasicReturnType>
+class MemberGetFuncDefinition final : public BasePointerDefinition {
 public:
-	using MemberFunc = ReturnType(Object::*)();
+	using MemberFunc = MemberType Object::*;
 
-	MemberFunctionPointerDefinition(VariableDefinition* underlying_definition, MemberFunc member_ptr)
-		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), member_ptr(member_ptr) 
+	MemberGetFuncDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_get_func_ptr)
+		: BasePointerDefinition(underlying_definition), member_get_func_ptr(member_get_func_ptr)
 	{
-		// static assert return type is reference or pointer
+		static_assert(std::is_member_function_pointer<MemberFunc>::value, "Must be a member function pointer");
 	}
 
-	bool Get(void* ptr, Variant& variant) override
-	{
-		return underlying_definition->Get(GetPointer(ptr), variant);
-	}
-	bool Set(void* ptr, const Variant& variant) override
-	{
-		return underlying_definition->Set(GetPointer(ptr), variant);
-	}
-	int Size(void* ptr) override
-	{
-		return underlying_definition->Size(GetPointer(ptr));
-	}
-	DataVariable Child(void* ptr, const DataAddressEntry& address) override
+protected:
+	void* DereferencePointer(void* base_ptr) override
 	{
-		return underlying_definition->Child(GetPointer(ptr), address);
+		return (void*)Extract((static_cast<Object*>(base_ptr)->*member_get_func_ptr)());
 	}
-
 private:
-	void* GetPointer(void* base_ptr) {
-		return (void*)Extract((static_cast<Object*>(base_ptr)->*member_ptr)());
-	}
 
 	// Pointer return types
 	BasicReturnType* Extract(BasicReturnType* value) {
@@ -364,20 +320,18 @@ private:
 		return &value;
 	}
 
-	VariableDefinition* underlying_definition;
-	MemberFunc member_ptr;
+	MemberType Object::* member_get_func_ptr;
 };
 
-
-
-template <typename Object, typename ReturnType, typename AssignType, typename UnderlyingType>
-class MemberScalarFunctionPointerDefinition final : public VariableDefinition {
+template<typename Object, typename MemberGetType, typename MemberSetType, typename UnderlyingType>
+class MemberScalarGetSetFuncDefinition final : public VariableDefinition {
 public:
-	using MemberFunc = ReturnType(Object::*)();
-
-	MemberScalarFunctionPointerDefinition(VariableDefinition* underlying_definition, MemberGetterFunc<Object, ReturnType> get_func, MemberSetterFunc<Object, AssignType> set_func)
-		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), get_func(get_func), set_func(set_func)
-	{}
+	MemberScalarGetSetFuncDefinition(VariableDefinition* underlying_definition, MemberGetType Object::* member_get_func_ptr, MemberSetType Object::* member_set_func_ptr)
+		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), member_get_func_ptr(member_get_func_ptr), member_set_func_ptr(member_set_func_ptr)
+	{
+		using MemberGetFunctionPtr = MemberGetType Object::*;
+		static_assert(std::is_member_function_pointer<MemberGetFunctionPtr>::value, "Must be a member function pointer");
+	}
 
 	bool Get(void* ptr, Variant& variant) override
 	{
@@ -390,48 +344,48 @@ public:
 
 private:
 
-	template<typename R = ReturnType, typename std::enable_if<std::is_null_pointer<R>::value, int>::type = 0>
+	template<typename T = MemberGetType, typename std::enable_if<std::is_null_pointer<T>::value, int>::type = 0>
 	bool GetDetail(void* /*ptr*/, Variant& /*variant*/)
 	{
 		return false;
 	}
 
-	template<typename R = ReturnType, typename std::enable_if<!std::is_null_pointer<R>::value, int>::type = 0>
+	template<typename T = MemberGetType, typename std::enable_if<!std::is_null_pointer<T>::value, int>::type = 0>
 	bool GetDetail(void* ptr, Variant& variant)
 	{
-		if (!get_func)
+		if (!member_get_func_ptr)
 			return false;
 
 		// TODO: Does this work for pointers?
-		auto&& value = (static_cast<Object*>(ptr)->*get_func)();
+		auto&& value = (static_cast<Object*>(ptr)->*member_get_func_ptr)();
 		bool result = underlying_definition->Get((void*)&value, variant);
 		return result;
 	}
 
-	template<typename A = AssignType, typename std::enable_if<std::is_null_pointer<A>::value, int>::type = 0>
+	template<typename T = MemberSetType, typename std::enable_if<std::is_null_pointer<T>::value, int>::type = 0>
 	bool SetDetail(void* /*ptr*/, const Variant& /*variant*/)
 	{
 		return false;
 	}
 
-	template<typename A = AssignType, typename std::enable_if<!std::is_null_pointer<A>::value, int>::type = 0>
+	template<typename T = MemberSetType, typename std::enable_if<!std::is_null_pointer<T>::value, int>::type = 0>
 	bool SetDetail(void* ptr, const Variant& variant)
 	{
-		if (!set_func)
+		if (!member_set_func_ptr)
 			return false;
 
 		UnderlyingType result;
 		if (!underlying_definition->Set((void*)&result, variant))
 			return false;
 
-		(static_cast<Object*>(ptr)->*set_func)(result);
+		(static_cast<Object*>(ptr)->*member_set_func_ptr)(result);
 
 		return true;
 	}
 
 	VariableDefinition* underlying_definition;
-	MemberGetterFunc<Object, ReturnType> get_func;
-	MemberSetterFunc<Object, AssignType> set_func;
+	MemberGetType Object::* member_get_func_ptr;
+	MemberSetType Object::* member_set_func_ptr;
 };
 
 

+ 1 - 1
Samples/invaders/src/HighScores.cpp

@@ -48,7 +48,7 @@ HighScores::HighScores(Rml::Context* context)
 	{
 		score_handle.RegisterMember("name_required", &Score::name_required);
 		score_handle.RegisterMember("name", &Score::name);
-		score_handle.RegisterMemberFunc("colour", &Score::GetColour);
+		score_handle.RegisterMember("colour", &Score::GetColour);
 		score_handle.RegisterMember("wave", &Score::wave);
 		score_handle.RegisterMember("score", &Score::score);
 	}

+ 2 - 2
Samples/invaders/src/HighScores.h

@@ -66,8 +66,8 @@ private:
 		int score;
 		int wave;
 
-		void GetColour(Rml::Variant& variant) {
-			variant = "rgba(" + Rml::ToString(colour) + ')';
+		Rml::String GetColour() {
+			return "rgba(" + Rml::ToString(colour) + ')';
 		}
 	};
 	using ScoreList = Rml::Vector< Score >;

+ 1 - 1
Samples/luainvaders/src/HighScores.cpp

@@ -48,7 +48,7 @@ HighScores::HighScores(Rml::Context* context)
 	{
 		score_handle.RegisterMember("name_required", &Score::name_required);
 		score_handle.RegisterMember("name", &Score::name);
-		score_handle.RegisterMemberFunc("colour", &Score::GetColour);
+		score_handle.RegisterMember("colour", &Score::GetColour);
 		score_handle.RegisterMember("wave", &Score::wave);
 		score_handle.RegisterMember("score", &Score::score);
 	}

+ 2 - 2
Samples/luainvaders/src/HighScores.h

@@ -66,8 +66,8 @@ private:
 		int score;
 		int wave;
 
-		void GetColour(Rml::Variant& variant) {
-			variant = "rgba(" + Rml::ToString(colour) + ')';
+		Rml::String GetColour() {
+			return "rgba(" + Rml::ToString(colour) + ')';
 		}
 	};
 	using ScoreList = Rml::Vector< Score >;

+ 17 - 0
Source/Core/DataVariable.cpp

@@ -85,4 +85,21 @@ DataVariable MakeLiteralIntVariable(int value)
     return DataVariable(&literal_int_definition, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
 }
 
+bool BasePointerDefinition::Get(void* ptr, Variant& variant) {
+    return underlying_definition->Get(DereferencePointer(ptr), variant);
+}
+
+bool BasePointerDefinition::Set(void* ptr, const Variant& variant) {
+    return underlying_definition->Set(DereferencePointer(ptr), variant);
+}
+
+int BasePointerDefinition::Size(void* ptr) {
+    return underlying_definition->Size(DereferencePointer(ptr));
+}
+
+DataVariable BasePointerDefinition::Child(void* ptr, const DataAddressEntry& address) {
+    // TODO: Return the constness of T?
+    return underlying_definition->Child(DereferencePointer(ptr), address);
+}
+
 } // namespace Rml

+ 5 - 3
Tests/Source/UnitTests/DataBinding.cpp

@@ -142,7 +142,7 @@ struct Basic
 	int GetD() {
 		return 4;
 	}
-	int& GetE() {
+	int& GetE() const {
 		static int e = 5;
 		return e;
 	}
@@ -277,6 +277,8 @@ struct Arrays {
 
 DataModelHandle model_handle;
 
+
+
 bool InitializeDataBindings(Context* context)
 {
 	Rml::DataModelConstructor constructor = context->CreateDataModel("basics");
@@ -301,7 +303,7 @@ bool InitializeDataBindings(Context* context)
 		handle.RegisterMember("a", &Basic::a);
 		handle.RegisterMember("b", &Basic::b);
 		handle.RegisterMember("c", &Basic::c);
-		handle.RegisterMemberScalar("d", &Basic::GetD);
+		handle.RegisterMember("d", &Basic::GetD);
 		handle.RegisterMember("e", &Basic::GetE);
 		handle.RegisterMember("f", &Basic::GetF);
 		handle.RegisterMember("g", &Basic::GetG);
@@ -314,7 +316,7 @@ bool InitializeDataBindings(Context* context)
 		handle.RegisterMember("a", &Wrapped::a);
 		handle.RegisterMember("b", &Wrapped::b);
 		handle.RegisterMember("c", &Wrapped::c);
-		//handle.RegisterMemberScalar("d", &Wrapped::GetD);
+		//handle.RegisterMember("d", &Wrapped::GetD);
 		handle.RegisterMember("e", &Wrapped::GetE);
 		handle.RegisterMember("f", &Wrapped::GetF);
 		handle.RegisterMember("g", &Wrapped::GetG);