模板相关内容笔记
一、模板泛化编程
(一)函数模板
1、函数模板定义方式:
template <class Type, int size>
Type min(const Type (&r_array)[size])
{
Type min_val = r_array[0];
for (int i = 1; i < size; ++i)
{
if (r_array[i] < min_val)
{
min_val = r_array[i];
}
}
return min_val;
}
2、模板参数
模板参数可以是一个模板类型参数,代表一种类型;可以是一个模板非类型参数,代表一个常量表达式 ;也可以是其他模板。
特殊说明:
- 在函数模板定义中声明的对象或类型不能与模板参数同名 ;
- 模板类型参数名可以被用来指定函数模板的返回值类型;
- 模板参数名在同一模板参数表中只能被使用一次 ,但可以在多个函数模板声明或定义之间被重复使用 ;
- 一个模板的定义和多个声明所使用的模板参数名无需相同;
// 三个 min() 的声明都指向同一个函数模板
// 模板的前向声明
template <class T> T min(T, T);
template <class U> U min(U, U);
// 模板的真正定义
template <class Type>
Type min(Type a, Type b) { /* ... */ }
3、函数模板实例化:
template <typename Type, int size>
Type min(Type (&p_array)[size]) { /* ... */ }
// pf 指向 int min( int (&)[10] )
int (*pf)(int (&)[10]) = &min;
typedef int (&rai)[10];
typedef double (&rad)[20];
void func(int (*)(rai));
void func(double (*)(rad));
void main()
{
func(&min);
}
- 函数模板在它被调用或取其地址时被实例化 ;
- 当函数模板被调用时,对函数实参类型的检查决定了模板实参的类型和值;
- 模板实参推演期间决定模板实参的类型时,编译器不考虑函数模板实例的返回类型;
- 左值转换(从左值到右值的转换、从数组到指针的转换、从函数到指针的转换)、限定修饰符转换和到一个基类(该基类根据一个类模板实例化而来)的转换 ;
- 多个函数实参可以参加同一个模板实参的推演过程 如果模板参数在函数参数表中出现多次,则每个推演出来的类型都必须与根据模板实参推演出来的第一个类型完全匹配 ;
- 定义一个普通函数,返回类型和**【参数表】**与另一个从模板实例化的函数的相同,调用时,普通函数优先,若只有声明没有定义,则链接失败;
(二)类模板
(三)trait和其他技巧
1、traits——Effective C++ 条款47
template<int EnumType>
struct TypeSet{};
template<>
struct TypeSet<EnumType1>
{
typedef Container vector<int>;
typedef Dlg CDialogFile;
};
template<>
struct TypeSet<EnumType2>
{
typedef Container set<int>;
typedef Dlg CDialogFont;
};
template<int Type>
void Fun()
{
TypeSet<Type>::Dlg* pDlg = new TypeSet<Type>::Dlg();
TypeSet<Type>::Container ctn();
/// .........
}
/// 静态表示类型信息
/// 非traits
struct Foo
{
enum {Type = 0};
};
struct Bar
{
enum {Type = 1};
}
template<class T>
void Fun()
{
if (T::Type == 0)
/// ......
else
/// .....
}
/// traits——1
template<typename T>
struct Traits
{
enum { T_Type = T::Type };
};
template<>
struct Traits<int>
{
enum { Type = 0 };
}
template<class T>
void Fun()
{
if (Traits<T>::Type == 0)
/// ......
else
/// .....
}
/// traits——2
struct Foo_tag{};
struct Int_tag{};
template<typename T>
struct Traits{};
template<>
struct Traits<int>
{
typedef Int_tag TraitTag;
};
template<>
struct Traits<Foo>
{
typedef Foo_tag TraitTag;
}
template<class T>
void Fun(const T& t)
{
doFun(t);
}
void doFun(const Int_tag&);
void doFun(const Foo_tag&);
2、静态断言
template <bool static_assert_failed>
struct static_assert_test;
template <>
struct static_assert_test<true>
{
enum { value = 1 };
};
template<unsigned int x> struct static_assert_v{};
template<typename T1, typename T2>
struct is_same
{
enum {value = false};
};
template<typename T>
struct is_same<T, T>
{
enum {value = true};
};
#define TYPE_STATIC_ASSERT static_assert_typedef##__COUNTER__
#define static_assert(B) \
typedef static_assert_v< sizeof( static_assert_test<(bool)(B)> ) > TYPE_STATIC_ASSERT
template<typename T>
void Fun(const T& t)
{
/// 只允许int、double 实例化模板
static_assert( (is_same<int, T>::value || is_same<T, double>::value) );
/// ....
}