使用背景
假如有个函数模板参数,假如必须是类型A,一般咋写呢?
template<int N, typename A>
A func(A* in)
{
return in[N];
}
func<3>(in);
这里有个问题,就是假如传入的是B类型的in,好像也能运行,但是我只要这个模板支持A类型咋办?我们知道C++中类是有偏特化的,而模板函数没有,C++提供了enable_if和true_type两种解决方案。
C++20
true_type
template <typename T>
struct is_limit: std::false_type {};
template <>
struct is_limit<Limit> : std::true_type {};
/*
template <typename T>
struct is_limit< Limit<T> > : std::true_type {};
template <int N>
struct is_limit< Limit<N> > : std::true_type {};
*/
template <typename T>
concept LimitLike = is_limit<T>::value;
template<int N, typename A, Limitlike>
void test();
test<1, float, Limit>();//ok
test<1, float, float>();//error
思想也比较简单,当你传入Limit时候,LimitLike这个模板类会接受一个Limit的类型参数,也就是这里的T是Limit,所以会选择true_type这个实现,如果传入其他类型,这里会走到false type类型,当编译器检测到模板参数里出现false_type的话就会编译报错。
enable_if
说实话,我觉得enable这种更加好理解,用concept很多人不了解或者编译器都不支持
template<int N, typename A, typename T, enable_if_t<is_limit<T>, bool> = true>
void test();
test<1, float, Limit>();//ok
test<1, float, float>();//error
简单解释一下,enable_if_t一旦条件是false的话,由于只有一个模板函数可以实例化,所以就会报出编译错误,而如果成功的话又必须搞一个type,这里用一个bool类型并且提供一个默认初始值true.
对于C++17之前没有concept的话使用如下:
模板
比葫芦画瓢先看看怎么使用,理解起来其实不难,但是基本模式要记住
template <typename T>
struct void_type {
using type = void;
};
template <typename T, typename = void>
struct has_limit: public std::false_type {};
//
template <typename T>
struct has_limit<T, typename void_type<typename T::limit>::type>
: public std::true_type {};
参考:https://blog.csdn.net/sunny_98_98/article/details/116136331
使用
一般哪里会有这个使用需求呢???struct has_limit有点类似于实现了一个enable_if的功能,通过类模板的偏特化特性, 下面是一个小demo,但是一般不这样直接使用。
struct Limit
{
using limit = int;
};
int main()
{
std::cout<<has_limit<int>::value<<std::endl; //0
std::cout<<has_limit<Limit>::value<<std::endl; //1
}
实际上使用:
template<typename T, bool dummy = has_limit<T>::value>
struct Real
{
};
template<typename T>
struct Real<T, false>
{
};
int main()
{
std::cout<<has_limit<int>::value<<std::endl; //0
std::cout<<has_limit<Limit>::value<<std::endl; //1
}
具体在一些cub框架里使用, 有一点小出入但是大体没区别,代码在cub/block/radix_rank_sort_operations.cuh
template <class... >
using void_t = void;
template <class T, class = void>
struct is_fundamental_type
{
static constexpr bool value = false;
};
template <class T>
struct is_fundamental_type<T, void_t<typename Traits<T>::UnsignedBits>>
{
static constexpr bool value = true;
};
template <class T, bool = is_fundamental_type<T>::value>
struct traits_t
{
using bit_ordered_type = typename Traits<T>::UnsignedBits;
}
template <class T>
struct traits_t<T, false /* is_fundamental */>
{
using bit_ordered_type = T;
using bit_ordered_conversion_policy = custom_bit_conversion_policy_t;
}
总结
我自己觉得就是实现一个enable_if的作用,但是看起来花里胡哨,不知道理解的是不是有问题,希望大佬指正。