类似:
fmt里判断是否为reference_wrapper-CSDN博客
现代C++之SFINAE应用(小工具编写)-腾讯云开发者社区-腾讯云
问题
第一个my_is_pair和第二个是什么关系,第一个的类型列表里只有一个参数:template<typename T>
。第二个只有两个:template<typename T, typename U>。第二个是偏特化?都偏特化了,类型参数的个数比泛化的还多?
template<typename T>
struct my_is_pair : std::false_type
{
};
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>> : std::true_type
{
};
template<typename T>
void fun_pair(T a, std::enable_if_t<my_is_pair<T>::value>* = 0)
{
}
std::pair<double, double> pairdata;
fun_pair(pairdata);
另一个版本
由于在这个例子里,false版本没有用到。所以my_is_pair的泛化版本没有实体,也是可以的:
template<typename T>
struct my_is_pair;
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>> : std::true_type
{
};
template<typename T>
void fun_pair(T a, std::enable_if_t<my_is_pair<T>::value>* = 0)
{
double m = 1;
std::cout << std::endl;
}
std::pair<double, double> pairdata;
fun_pair(pairdata);
泛化版本类型列表里类型的个数和偏特化一样时,反而提示my_is_pair的模板参数太少
但是my_is_pair列表里添加了一个类型,却编不过,提示my_is_pair的模板参数太少。
template<typename T, typename U>
struct my_is_pair;
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>> : std::true_type
{
};
template<typename T>
void fun_pair(T a, std::enable_if_t<my_is_pair<T>::value>* = 0)
{
}
std::pair<double, double> pairdata;
fun_pair(pairdata);
说明:考虑到第一个my_is_pair只有一个typename T,那么第二个my_is_pair(my_is_pair<std::pair<T, U>>)里面的std::pair<T, U>算是一个参数。
如果第一个改成:
template<typename T, typename U>
struct my_is_pair;
那么第二个my_is_pair里面必须也得有第二个类型,比如这样就能编译成功:
template<typename T, typename U>
struct my_is_pair : std::false_type
{
};
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>,U> : std::true_type
{
using first = T;
using second = U;
};
//T:std::pair<double, double>
template<typename T>
void fun_pair(T a, std::enable_if_t<my_is_pair<T,double>::value>* = 0)
{
typename my_is_pair<T,double>::first x{};
typename my_is_pair<T,double>::second y{};
std::cout << x << std::endl;
std::cout << y << std::endl;
std::cout << 1 << std::endl;
}
std::pair<double, double> pairdata;
fun_pair(pairdata);
或者这样也可以:
学到了。确实是这样。
template<typename T, typename U>
struct my_is_pair : std::false_type
{
};
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>,U> : std::true_type
{
using first = T;
using second = U;
};
//T:std::pair<double, double>
template<typename T>
void fun_pair(T a, std::enable_if_t<my_is_pair<T,typename T::second_type>::value>* = 0)
{
typename my_is_pair<T,T::second_type>::first x{};
typename my_is_pair<T,T::second_type>::second y{};
std::cout << x << std::endl;
std::cout << y << std::endl;
std::cout << 1 << std::endl;
}
std::pair<double, std::string> pairdata;
fun_pair(pairdata);
分析
果然,编译器先对泛型版本进行处理,
比如用std::pair<double,std::string> 进行推导,先找到泛化版本。
template<typename T>
struct my_is_pair : std::false_type
{
};
此时T被推导为std::pair<double,std::string>,可以理解为:my_is_pair<T>变成my_is_pair<std::pair<double,std::string>>,这个时候,pair里的first和second的类型是随着整个pair去匹配泛化版本的T的。
然后接着匹配,发现了更合适的偏特化版本(结构):my_is_pair<std::pair<*,*>>
template<typename T, typename U>
struct my_is_pair<std::pair<T, U>> : std::true_type
{
};
往上一套(推导),这时T->double, T->std::string。
所以,得看推导的过程。编译器不去比较谁的类型参数更多。
这就是为什么泛化版本的类型列表里的个数,比偏特化的少,最后还能匹配上,这是由编译器处理的顺序决定的。