我可以重用同一个模板来声明/定义多个东西吗(而不复制模板代码)

Can I reuse the same template to declare/define multiple things (without duplicating the template code)?

本文关键字:复制 代码 同一个 声明 我可以 定义      更新时间:2023-10-16

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

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是一个函数可以以以下两种格式之一返回数据:如果模板参数Tint可以转换成的类型,然后是积分返回数据的表示形式(从而触发转换到所请求的类型,我们知道这是可能的)。如果T是什么可以由string构造,然后由string构造返回数据的表示形式(再次触发从CCD_ 9构造CCD_ 8)。任何其他类型落入这些类别将简单地导致编译时错误,这正是这个代码想要做的

这个类还定义了简单的转换运算符,这些运算符是根据get编写的。

既然这些操作符使用了与get的相应定义完全相同的模板,我能以某种方式避免复制所有讨厌的模板代码吗?我可以重用一行模板代码来定义多个内容,使代码更可读吗?

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

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

此外,对于多个SFINAE,您可以更改enable_if_t以获得默认的int:,而不是不断添加额外的typename=void

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>()上的测试会失败,但这似乎不是通常可以测试的。