如下的源码:
template<typename T, typename U = int>
class S{ //#1
public:
void f1(){};
};
template<>
class S<void> { //#2
public:
void f2(){};
};
int main()
{
S<void, int> sv; // OK: uses #2, definition available #3
//sv.f1();//error
sv.f2();//ok
}
clang模板展开时,#3变成:
S<void> sv = S<void>();
为啥S<void, int> 不走主模板分支 #1?
其实 #2 的实现,S<void> 就是 S<void,int>。
实现过程:
class S<void> 的实例化,查找到前面有主模板定义:
template<typename T, typename U = int> class S
因为第二个模板参数默认值是int所以 会自动生成
S<void, int>
也就是说,class S<void> 根据主模板,就是 S<void, int>。
接下来就是 S<void, int> 选择哪个匹配问题。根据模板匹配找最适合的,范围更小的。最终选定偏特化的,主模板的范围太广了。
再看一个小的示例:
//这个是主模板
template<bool, typename T= void> //这个T,可以省略,因为没有被引用
struct en_if {};
//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T>
struct en_if <true, T> { using TYPE = T; };
/////------
en_if<true>::TYPE* a;
en_if<true>,这个根据主模板,形成: en_if<true, void>。(会去主模板,没提供 T,默认是void,最终 T就变成了 void)。
接下来 en_if<true, void>选择主模板,还是偏特化的问题。
主模板:template<bool,typename T=void>
偏特化:en_if<true, T>
偏特化更符合,范围更小。即符合偏特化,肯定符合主模板;符合主模板,不一定符合偏特化。
偏特化被改的话,都会报错:
//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T=void>
struct en_if <true, T> { using TYPE = T; };
//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T=int>
struct en_if <true, T> { using TYPE = T; };
上面两种修改都会导致报错:
error: default template argument in a class template partial specialization
template< typename T=void>
^
1 error generated.
实际应用
通过默认模板参数 来选择默认的特化版本,当条件不成立时,退回到主模板。- 当默认模板参数是类型,则一般为void,并在特化版本通过void_t或者 enable_if_t选择;
- 若为值,则用bool常量表达式结果作为默认参数并在特化版本中通过true false选择。
以上摘自《c++20高级编程》罗能 p64.
enable_if 作为约束使用,它虽然出现在模板上的一个参数,但是没有用,只是作为模板模式匹配用途。在c++20用约束来替换。
1, 关于默认值的模式匹配
template<bool B, class T=long>
struct enable_if{};
template<class T>
struct enable_if<true,T>{
using type = T;
};
enable_if<true>::type a;
可以看到,a是个 long 类型。
template<bool B, class T = long>
struct enable_if
{
};
/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct enable_if<true, long>
{
using type = long;
};
#endif
template<class T>
struct enable_if<true, T>
{
using type = T;
};
enable_if<true>::type a;
2,它真正用途是作为 选择器。上面的long其实没用,用void代替。
#include <iostream>
template<bool B, class T=void>
struct enable_if{};
template<class T>
struct enable_if<true,T>{
using type = T;
};
template<class T, class U=typename enable_if< std::is_integral_v<T> >::type >
struct X{
};
X<int> ok;
X<std::string> compile_failed;
由于enable_if<false> 会匹配主模板定义,而里面是没有 type 这个定义的。所以导致 compile_failed。
可以看到上面的 class U模板参数只是作为约束存在,没有任何实际意义。c++20用 concept。
#include <iostream>
template<class T>
concept IntType= std::is_integral_v<T>;
template<IntType T>
struct X{
};
X<int> ok;
//X<std::string> compile_failed;
进一步可以简化为:
template<class T>
requires std::is_integral_v<T>
struct X{
};
X<int> ok;
标签:enable,struct,void,c++,template,默认值,模板,特化 From: https://www.cnblogs.com/bigben0123/p/16919311.html