C++中的可扩展类型特征

m.s*_*.s. 12 c++ templates type-traits c++14

我想编写一个通用的序列化库,它提供了一个通用的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 ;
};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

save应该可以为用户数据类型进行自定义,不仅可以通过重载,还可以通过特征进行自定义.因此我创建了trait_extension哪些可以专门用于特征模板:

template <template<typename> class Trait, typename T>
struct trait_extension : Trait<T>
{
}
Run Code Online (Sandbox Code Playgroud)

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) { ... }
Run Code Online (Sandbox Code Playgroud)

用户现在可以提供自己的专长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;
};
Run Code Online (Sandbox Code Playgroud)

我的问题::

是否有一种"更好"/更优雅的方式来实现可扩展的特征?

live example

小智 2

我认为你的方法一点也不优雅。它很容易变成意大利面条式代码,并使其难以维护或使用。相反,我会采用基于“策略”的方法,类似于std::allocator标准库中的类。更改行为很简单,只需实现分配器接口并将其作为模板参数提供即可。然后一切都会自动解决。

一方面,在“通用序列化”库中,您不仅需要担心类型,还需要担心本地化。它可以像使用,“替代”一样简单.,也可以像统一大写一样复杂。使用您的方法,修改流或区域设置(即 std 与 boost)后端并不是很容易,但是使用基于策略的方法,这是搜索和替换的问题:

serialize<int, std_locale<int>>(32.000)
serialize<int, boost_locale<int>>(32.000)
Run Code Online (Sandbox Code Playgroud)

这允许您在主语言环境类 ala 中提供一组“默认值” std::allocator,然后用户可以从该类继承并更改一种或两种类型的行为,而不是提供疯狂的 SFINAE 重载。