我可以重复使用相同的模板来声明/定义多个事物(不重复模板代码)吗?

时间:2016-05-20 18:09:45

标签: c++ templates

我目前正在编写一个类,它有一些花哨的模板来定义它的一些成员,但其中一些模板完全相同。请考虑以下代码(这些都是类成员):

template <typename T, typename = enable_if_t<is_convertible<int, T>::value>>
T get() const { return convert_self_to_int(); }

template <typename T, typename = enable_if_t<is_constructible<T, string>::value>, typename = void>
T get() const { return convert_self_to_string(); }

template <typename T, typename = enable_if_t<is_convertible<int, T>::value>>
operator T() const { return get<T>(); }

template <typename T, typename = enable_if_t<is_constructible<T, string>::value>, typename = void>
operator T() const { return get<T>(); }

正如您所看到的,我有一个名为get的模板化成员函数,该函数使用较长且难以阅读的模板代码。

  

这部分对于这个问题并不重要,但这里是对所有这些花哨模板的简要说明:get是一个函数,   可以使用以下两种格式之一返回数据:如果模板参数T是   可以转换int的类型,然后是积分   返回数据的表示(从而触发转换   到我们知道可能的请求类型。如果T是某种东西   可以从string构建,然后string   返回数据的表示(再次,触发数据   从T构建string。任何其他没有的类型   落入这些类别只会导致编译时错误,   这正是这段代码的目的。

此类还定义了简单的转换运算符,这些运算符以get

的形式编写

既然这些运营商使用完全相同的模板作为get的相应定义,我能以某种方式避免重复所有讨厌的模板代码吗?我可以重用一行模板代码来定义多个东西,使代码更具可读性吗?

1 个答案:

答案 0 :(得分:2)

您可以使用SFINAE将operator T()转发至get<T>。这样,您只需要一个operator T()

template <class T, class = decltype(std::declval<ClassName>().get<T>())>
operator T() const { 
    return get<T>();
}

此外,对于多个SFINAE,您可以更改typename=void,而不是不断添加其他enable_if_t,以便为您提供默认int

template <class T, std::enable_if_t<std::is_convertible<int, T>::value, int> = 0>
T get() const { return convert_self_to_int(); }

template <class T, std::enable_if_t<std::is_convertible<std::string, T>::value, int> = 0>
T get() const { return convert_self_to_string(); }

现在,这不会在clang中起作用,所以我只是建议翻转顺序。让operator T()成为SFINAE-d:

template <class T, std::enable_if_t<std::is_convertible<int, T>::value, int> = 0>
operator T() const { return convert_self_to_int(); }

template <class T, std::enable_if_t<std::is_convertible<std::string, T>::value, int> = 0>
operator T() const { return convert_self_to_string(); }

只有get前进:

template <class T> T get() const { return operator T(); }

这里的优点是我们不会复制任何内容,std::is_convertible<>类型特征将正常工作 - 因为operator T()是SFINAE-d。对get<T>()的测试将失败,但这似乎不是通常可测试的东西。