通过这几个例子,暂时有个结论:
基本就是:由泛型版本定下参数列表里的参数,
编译成功:template<bool _Test, class _Ty = void>
struct enable_if123;template<class _Ty>
struct enable_if123<true, _Ty>
{ // type is _Ty for _Testusing type = _Ty;
};int main()
{if (1 == std::is_void<std::enable_if<true>::type>::value){int i = 0;i++;}enable_if123<true>::type t1;
}
给出另外一个版本,试图在偏特化的参数<>里切换成std::wstring,但编译出现了
错误,大意是推导不出来
关键是:都没有实例化的代码,光编译器前期的检查都通不过。template<bool _Test, class _Ty = double>
struct enable_if123;
//{//using type = _Ty;
//};template<class _Ty>
struct enable_if123<true, typename std::enable_if<std::is_floating_point<_Ty>::value, std::wstring>::type>
{ // type is _Ty for _Testusing type = _Ty;
};int main()
{
return 1;
}error C2764: “_Ty”: 部分专用化“enable_if123<true,std::enable_if<std::is_floating_point<_Ty>::value,std::wstring>::type>”中未使用或不能推导出的模板参数
部分专用化中不使用模板参数。
这使得部分专用化不可用,因为无法推导模板参数。
看这个例子,好像和上面的enable_if又有点不同:
实例化的时候用了A<double,std::wstring>
所以偏特化的第二个参数,如果推导出来不是std::wstring,
这个偏特化版本是匹配不上的。也就是说第二个参数如果没有推导,就像enable_if偏特化版本的第二个参数enable_if<true,_Ty>,
那么编译器就直接把泛型推导中的第二个参数赋给它。
如果有推导,那么推导结果必须和泛型的第二个参数一样。否则就匹配不上,或者报错。template<class T, class Enabled = double>
class A;template<class T>
class A<T, typename/*这个typename不可少*/ std::enable_if<std::is_floating_point<T>::value, std::wstring>::type> {
public:A(){std::cout << "partial specialization\r\n";}
}; // specialization for floating point typesint main123() {A<double,std::wstring> a;int m = std::is_floating_point<double>::value;++m;return 1;
}
运行结果:partial specialization————————————————根据上一个例子的解释,把偏特化的第二个参数的推导过程稍微改一下,把std::wstring改成T。
发现它匹配的是泛型版本。而泛化版本里没有定义value,所以编译出错。因为什么呢,根据泛型版本推导出来T:double, Enabled:std::wstring
在用此组参数去检查偏特化版本的时候,发现第二个参数推导出来也是double
这样就成了T:double, Enabled:double
所以这个偏特化就匹配不上了,因为是以泛型的推导结果为主,所以这个偏特化就匹配不成功。template<class T, class Enabled = double>
class A;template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value, T>::type> {
public:A(){std::cout << "partial specialization\r\n";}
}; // specialization for floating point typesint main123() {A<double, std::wstring > a;int m = std::is_floating_point<double>::value;++m;return 1;
}
编译结果:
error C2079: “a”使用未定义的 class“A<double,std::wstring>”版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/tumu_C/article/details/137350079
struct NoInnerType
{int m_i;
};struct HaveInnerType
{using type = int; //类型别名void myfunc() {}
};//泛化版本
template <typename T, typename U = std::void_t<> >
struct HasTypeMem : std::false_type //struct 默认是public ,class默认是private继承
{
};
//特化版本
template <typename T>
struct HasTypeMem<T, std::void_t<typename T::type> > : std::true_type
{
};std::cout << HasTypeMem<NoInnerType>::value << std::endl; //0
std::cout << HasTypeMem<HaveInnerType>::value << std::endl; //1按照上面的结论,
泛化版本对HasTypeMem<NoInnerType>的推导结果是HasTypeMem<NoInnerType,void>
以此为基础,去看偏特化版本:
偏特化版本的第一个参数是NoInnerType,第二个参数是void,没啥问题
但第二个void里面带有推导逻辑。由于NoInnerType里面没有type,所以推导不成功,最后采用的是泛化版本看看这个例子,其实偏特化版本实例化之后的第二个参数,最后的结果也是void
刚好和泛型里面的对应上。只不过偏特化的第二个参数里面,带有推导的作用。
起到了一定的约束。----------------------------------------------------------
要是不加约束呢,那么偏特化版本都能匹配成功。最后输出都是1struct NoInnerType
{int m_i;
};struct HaveInnerType
{using type = int; //类型别名void myfunc() {}
};//泛化版本
template <typename T, typename U = std::void_t<> >
struct HasTypeMem : std::false_type //struct 默认是public ,class默认是private继承
{
};
//特化版本
template <typename T>
struct HasTypeMem<T, std::void_t<> > : std::true_type
{
};std::cout << HasTypeMem<NoInnerType>::value << std::endl; //1
std::cout << HasTypeMem<HaveInnerType>::value << std::endl; //1