所谓Type trait,提供了一种用来处理type 属性的办法,它是个template,可在编译期根据一个或多个template实参(通常也是type)产出一个type或者value。
templatevoid foo(const T& val) { if (std::is_pointer ::value) { cout << "foo called for a pointer " << endl; } else cout << "foo() called for a value" << endl; //... }
trait std::is_pointer定义于
但是,不能如下这么做:
templatevoid foo(const T& val) { std::cout << (std::is_pointer ::value ? *val : val) << endl; }
关键是不确定val到底是指针还是普通值。若是个值得话,*val 就无效了,不能通过编译。
templatevoid fool_impl(const T& val,std::true_type){ cout << "foo() called for pointer to " << *val << endl; } template void fool_impl(const T7 val, std::false_type){ cout << "foo() called value to "<< val << endl; } template void foo(const T& val){ fool_impl(val,std::is_pointer ()); }
这比重载版本要好。是因为,有时候太多重载版本并无必要。一般而言,type trait 的威力来自于一个事实:它们是泛型代码的基石。
两个例子:
1 针对整数的弹性重载
假设一个函数foo(),对于整数类型和浮点类型的实参有不同的实现。通常做法是重载:
void foo(short); void foo(unsigned short); void foo(int); ... void foo(float); void foo(double); void foo(long double);
每多一个类型,就需要一个新的重载函数。但是,有了type trait就是不一样:
templatevoid foo_impl(T val, true_type); template void foo_impl(T val, false_type); template void foo(const T& val){ fool_impl(val,std::is_integral ()); }
只需提供两份实现,整数和浮点,完事儿。
2 处理共通类型
共通类型是一个可以“用来处理两个不同类型的值”的类型,前提是存在这个一个共通类型。举例而言,不同类型的两个值的总和或最小值,就该使用共通类型。
templatetypename std::common_type ::type min(const T1& x, const T2& T);
如果两个实参都是int 或者都是long,或者一个是int一个是long,std::common_type
templatestruct common_type { typedef decltype(true ? decval () : decval ()) type; };
其中 decltype是c++11提供的关键字,用以到处表达式类型,declval()是辅助性trait,依据传入的类型提供一个值 ,但是不去核算它。
该头文件下的函数等 。cppreference.com