CPP {模板类,类的全特化/偏特化}
模板类
错误
#模板类 声明和实现 必须放到头文件里#
a.h: template<T> struct ST{ void F();}
, 然后你a.cpp: template<T> ST<T>::F(){ ...}
;
这是错误的, 到时候b.cpp
里 是找不到的;
.
有个疑问: std::vector::emplate_back
他的实现放哪了?(因为他是动态库 所以情况不同?)
性质
#模板类的自动推导#
vector A( 3, vector<int>( 5))
, 这个3*5
的二维数组 不用写成vector<vector<int> > A
直接写一个vector
他可以自动推导;
vector A( mp.begin(), mp.end())
, 他自动推导为vector< pair<Key, Value> >
;
他是通过构造函数来推导的, 比如template< class _T_> struct ST_{ ST_( _T_){} };
, 当你调用ST_ a(123)
时 他自动推导为ST_<int>
;
@DELI;
template<?,?>
裡面的constexpr
(準確來說 必須是static constexpr
)都是完全相同的!
.
即<int,1>
與<char,2>
的 constexpr
常量 都是一樣的;
.
即 雖然模板類就是(代碼) 即好像同一個類 的不同模板 好像是很不同的, 但是 他們的constexpr
都是一樣的;
<int,1>
與<char,2>
裡面的 static const
常量 都是一樣的; 比如: template<class A, int B> class ST{ static const A M = B;};
那麼<int,1>::M
等於int 1
, 而<char, 2::M
等於char 2
, 他們是不同的;
@DELI;
template< int A> ST;
类模板中的A, 且他必須是is_integral
的, 即<bool/char/int... A>
是可以的 但是<double A>
是錯誤的;
他接收的實際參數 必須是constexpr
的, 比如const int a1 = rand(); constexpr int a2 = 123;
那麼ST<a2>, ST<3>
是可以的, 而ST<a1>
是錯誤;
@DELI;
template< class A, int B>
class ST{
};
ST<int,123> x;
我们如何通过x
对象 来获取其A|B
的值呢(即int|123
);
做法是:
template< class A, int B>
class ST{
using AA = A;
static constexpr int BB = B;
};
然后通过decltype(x)::AA/BB
就可以获得int/123
;
模板类的全特化/偏特化
算法
根据不同类型 执行不同函数
对于模板函数, 如果其模板参数为整型 就执行逻辑A, 否则执行逻辑B;
.
一个错误做法是: template<T> Func( T _t){ if( std::is_tegeral_v<T>){ A...} else{ B...} }
; 因为比如A...
里面有_t *= 2
操作, 可是假如T==string
此时虽然不会进入A...
但编译器在编译期间 他可不知道 他还是会执行string *= 2
发现是未定义的 即编译错误;
.
再看一个错误做法: 把A...
替换成Handle_integral()
函数, 即把A..., B...
代码逻辑 用单独的函数来替换; 你可能认为这样就能蒙混过关了, 其实也是错的… 因为他俩本质上是一样的! 即还是会调用Handle_integral( string)
依然是编译错误;
因此 基本上 永远不要在函数里 执行if( 编译期判断(诸如std::is_same_v) ){ ...}
, 这是错误的, 因为类型是编译期 而函数是运行期;
正解是: 偏特化模板类; (可参考SUPIMO::toString
的设计);
template< class _T, int8_t _Check> struct __work;
template< class _T> struct __work<_T, 0>{ // Integral
static void Func( _T _t){ _t一定是整型}
};
template< class _T> struct __work<_T, 1>{ // Non-Integral
static void Func( _T _t){ _t一定不是整型}
};
template< class _t> struct Work : __work<_t, (std::is_integral_v<_t> ? 0 : 1)>{};
调用: `T t;` `Work<T>::Func( t);`