我想写一个通用的序列化库,它提供了例如通用save
函数。
该库包含自定义类型特征,例如some_condition
:
template <typename T>
struct some_condition
{
constexpr static bool value = std::is_same<std::string, T>::value ||std::is_arithmetic<T>::value ;
};
save
的行为是根据some_condition
选择的:
template <typename T>
std::enable_if_t<some_condition<T>::value> save(const T& value)
{
std::cout << "these types will be handled in a specific way: " << value << std::endl;
}
template <typename T>
std::enable_if_t<!some_condition<T>::value> save(const T& value)
{
std::cout << "these types will be handled in another way: " << value << std::endl;
}
save
可以为用户数据类型进行自定义,不仅可以通过重载,还可以通过特征进行自定义。
因此,我创建了trait_extension
,它可以专门用于特征模板:
template <template<typename> class Trait, typename T>
struct trait_extension : Trait<T>
{
}
必须相应地修改 save
:
template <typename T>
std::enable_if_t<trait_extension<some_condition,T>::value> save(const T& value) { ... }
template <typename T>
std::enable_if_t<!trait_extension<some_condition,T>::value> save(const T& value) { ... }
用户现在可以提供自己的trait_extension
专业化:
template <typename T>
struct trait_extension<some_condition, T>
{
// user specific extension: exclude floats from condition
constexpr static bool value = !std::is_floating_point<T>::value && some_condition<T>::value;
};
我的问题::
是否有更好的&#34; /更优雅的方式来实现可扩展的特征?
答案 0 :(得分:1)
我认为你的方法很优雅。它可能很容易陷入意大利面条代码,使其难以维护或使用。我会采用一种基于策略的方法,类似于标准库中的std::allocator
类。更改行为是实现分配器接口并将其作为模板参数提供的简单问题。然后一切都会自动完成。
首先,在#34;通用序列化&#34;库,你不仅要担心类型,还需要担心本地化。它可以像使用,
而不是.
一样简单,也可以像统一大写一样复杂。使用您的方法,修改流或区域设置(即std vs boost)后端并不是很容易,但使用基于策略的方法则需要搜索和替换:
serialize<int, std_locale<int>>(32.000)
serialize<int, boost_locale<int>>(32.000)
这允许您提供一组&#34;默认值&#34;比如说一个主语言环境类ala std::allocator
,然后用户就可以继承它并改变一种或两种类型的行为,而不是提供疯狂的SFINAE重载。