[英]Conditionally enable a sub-type (similar to enable_if to enable functions)
我有一个traits类,它通过推导成员函数的类型来定义“范围”(或容器,序列)的类型,如下所示:
template<class R>
struct range_type_traits
{
// "iterator": The type of the iterators of a range
using iterator = decltype(std::begin(std::declval<R>()));
// "value_type": The (non-reference) type of the values of a range
using value_type = typename std::remove_reference<decltype(*(std::declval<iterator>()))>::type;
};
我这样做的原因(并没有直接使用R
的子类型或std::iterator_traits
)是为了支持某个带有begin()
成员的模板库中的任何类型的容器,并且不要求容器有一些value_type
/ iterator
类型已定义。 据我所知, std::iterator_traits
无法处理某些类型的“密钥类型”,这些容器不会使用对象将其迭代器接口暴露给STL,例如std::map
do(例如: QMap<K,T>
has value_type = T
您可以通过iterator::key()
访问密钥。)。
现在我想有条件地定义一个类型key_type
,如果iterator
有一个function ::key() const
并采用它的返回类型,类似于我对value_type
。 如果我只是将定义放在现有的traits类中,那么对于不支持此类的容器,编译就会失败。
带有std::enable_if
SFINAE可以有条件地启用模板功能。 如何有条件地扩展现有类/有条件地定义子类型?
像这样的草图:
template<class R>
struct range_type_traits
{
// "iterator": The type of the iterators of a range
using iterator = decltype(std::begin(std::declval<R>()));
// "value_type": The (non-reference) type of the values of a range
using value_type = typename std::remove_reference<decltype(*(std::declval<iterator>()))>::type;
ENABLE_IF_COMPILATION_DOES_NOT_FAIL {
// "key_type": The (non-reference) type of the keys of an associative range not using pairs in its STL-interface
using key_type = typename std::remove_reference<decltype(std::declval<iterator>().key())>::type;
}
};
您可以在类模板上使用SFINAE来创建基类模板,当且仅当满足您需要的条件时才定义key_type
:
namespace detail
{
// Primary template (does not define key_type)
template<typename R, typename = void>
struct key_type_definer { };
// Specialization using SFINAE to check for the existence of key() const
// (does define key_type)
template<typename R>
struct key_type_definer<
R,
typename std::enable_if<
std::is_same<
decltype(std::declval<R const>().key()),
decltype(std::declval<R const>().key())
>::value
>::type
>
{
// Type alias definition
using key_type = typename std::remove_reference<
decltype(std::declval<R const>().key())
>::type;
};
} // end namespace detail
然后,你可以得到你的range_traits
从类模板key_type_definer
类模板,像这样:
template<class R>
struct range_type_traits : detail::key_type_definer<R>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
// ...
};
range_type_traits
现在将定义一个名为key_type
的类型别名,当且仅当R
具有成员函数R key() const
,其中R
将是key_type
别名的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.