SVG属性类设计 (3)
需求
在SVG属性类设计(1)中,定义了基本SVG属性类,提供了泛型的实现方式。接下来我们需要让SVG属性能进一步适配枚举型属性,例如"a|b"的类型要求。(具体的例子:rect元素中的cx ,其合法属性为"<number>|<length>" )。由于其性质和元组一致,称之为属性元组。
属性枚举的特点是包含多个不同的类型,且选取第一个非空合法类型值作为最终类型。
设计
属性枚举既有容器的性质又是属性,因此要包含泛型组件中的所有操作。
-
底层容器 仍然使用泛型容器std::tuple -
构造 构造时遍历内部维护的_tuple ,依次设置getter和setter为。 -
提交与取值 属性枚举虽然是容器,但其中的所有属性类型不能独立存在。提交时并不需要将各属性依次提交,只需获取缓冲区。 遍历所有内部属性的提交区,最终的取值是第一个获取的非空值。 -
赋值、绑定 对所有内部属性分别操作即可。
细节
对于模板、参数展开等问题均在上一篇中说明,此处不再赘述。
-
函数静态类型转换 绑定函数时发现存在静态转换问题,即: std::function<T()>
与 (T*)()
以及 [](){ return T(); }
在泛型下无法进行直接推导。 最终考虑分开处理,对函数指针独立写一个新的泛型成员函数。但是lambda函数并没有好的解决方法。 -
Lambda函数的静态类型转换
-
尝试一:static_cast 手动进行静态类型转换,但是没法推导Lamdba函数的类型。了解到Lambda函数类型是编译器推导的一个函数对象(Functor),并不能直接获取 -
尝试二:decltype 尝试用在static_cast基础上使用decltype对Lambda函数类型进行推导。随后发现C++11中不支持,高版本能支持。 -
最终解决方法:完全泛型+显式转换 考虑重载一个泛型成员函数接受所有类型,然后尝试对该类型进行显式转换为std::function。 具体的显式转换如下: namespace detail {
template <typename F>
struct function_traits : public function_traits<decltype(&F::operator())> {};
template <typename R, typename C, typename... Args>
struct function_traits<R (C::*)(Args...) const>
{
using function_type = std::function<R (Args...)>;
};
}
namespace Lewzen {
template <typename F>
using function_type_t = typename detail::function_traits<F>::function_type;
template <typename F>
function_type_t<F> lambda_to_function(F & lambda) {
return static_cast<function_type_t<F>>(lambda);
}
}
先通过模板元编程,结合Lambda函数作为Functor的特性,利用其括号运算符重载,获取返回类型R、参数列表Args…,Lambda的原始类型C,进而协助进行静态类型转换为std::function。 -
返回只读类型的std::function作为参数的泛型函数重载问题 测试中发现Lambda函数的返回类型并非只读,因此无法有限匹配到返回值只读作为参数的重载,造成递归无限循环。但理论上是能直接静态类型转换的。 解决方法:另外创建一个函数,与返回值只读作为参数的重载参数列表相同,名称不同。强制Lambda对应的重载调用该函数。
|