C++ MetaProgramming

C++ MetaProgramming


前言

Note From:CppCon 2015: Fedor Pikus “C++ Metaprogramming: Journey from simple to insanity and back
MetaProgramming can be used in :

  1. calculation during compiling
  2. code genereation to boost runtime
  3. self-adaptive code
  4. type check and cast
  5. Type Dependent Code
  6. SFINAE-Selective Compile

一、Basic On Template

  1. Specialization and instantization
    特化分为显示特化和实例化,实例化又分为显示实例化和隐式实例化。
  2. Template explicit instantization
//函数
template int func<int>(int);
//类
template class Array<char>//成员函数
template class Array<char>::getSize();
  1. 模板显示特化(具体化):
//函数
template<> int func<int>(int){...};
//类
template <> class Tuple<int, double>{...};
  1. 模板类外定义:
//成员函数
template<typename T>
Array<T>& Array<char>::operator+(const Array<char>& arr){...};
//非const的static变量
template<typename T> 
int Array<T>::sharedInstance= 0; //每一个instance共享
//注:若让所有模板instance共享一个变量,则将共享变量放在一个非模板基类中
class Base {static int count = 0};
template<typename T> Derive: public Base{...};
  1. leading typename 和 dot template:
//模板编译分两步,读模板和实例化,读时遇到一些符号编译器不知是Type/object/func,一般两种情况:
//leading template告诉编译器此符号为一个Type。
template<typename T>
typename T::size_type munge(const T& t){
	typename T::size_type * i(T::npos);
}
//dot template(obj.template)告诉编译器该符号是一个隶属于obj的模板成员函数:
struct ExampleClass{ template <typename U> void m(); }; //成员函数为模板
ExampleClass ex;
ex.template m<int>(); //需要ex.template,不然编译不过

二、MetaProgramming的常用工具:模板类

1.enum/static constexprValueType的实现v(no variable in MetaProgramming)

// ::Value
template <size_t N> struct IsEven{
	enum { value = ( N  %2 ) ? 0 : 1 };
};
template <typename T> struct SizeOfT{
	static constexpr unsigned value = sizeof(T);
};
SizeOf<T>::Value
// ::Type
template <typename T> struct TPtr{
	typedef T* type;
}

2. Partial Specialization: RemoveConst

// remove_const
template<typename T> struct remove_const{ typedef T type; };
template<> struct remove_const<const T>{ typedef T type; };
// remove volatile
template<typename T> struct remove_volatile{ typedef T type; };
template<> struct remove_volatile<volatile T>{ typedef T type; };
// remove_cv
template<typename T> struct remove_cv{
	typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};

3. Specialization: Check Type

// is_char
template<typename T> struct is_char{ enum { value = 0 }; };
template<> struct is_char<char>{ enum { value = 0 }; };
// isAnyChar (char with cv)
template<typename T> struct isAnyChar{
	enum { value = is_char<std::remove_cv<T>::type>::value };
}

4. Recursion (Done by Partial Specialization)

template<size_t N> struct Sum{
	enum { value = N + Sum<N-1>::value }};
template<> struct Sum<1> {
	enum { value = 1 };
};

三、MetaProgramming的用武之地

1. 编译时数值计算:(constexpr函数也可以)

(1). Log(N)

template <size_t N> struct Log2 {
	enum { value = 1 + Log2<N/2>::value };
}
template <> struct log2<1> {
	enum { value = 0 };
}
// or use constexpr function
constexpr size_t log2(size_t n){
  return (( n<2 ) ? 1 : 1 + log2( n/2 ));
}

(2). If-then-else (std::conditional)

template <bool B, typename T, typename U> struct conditional{
	typedef T type;
}
template <typename T, typename U> struct conditional<false, T, U>{
	typedef U type;
}
// or value if use size_t

(3). Compile assert before C++11

template <size_t N> struct isPowerOf2{
	enum { value = (N & (N-1)) };
};
template <bool C> struct StaticAssert; // undefine
template <> struct StaticAssert<true> {};

2. 代码生成 (Code generation) 加速运算

(1). generate by template argument (Pow<N>()(x), faster than std::math)
一个广泛的错误写法

// 产生了很多模板函数 Pow<N>()(double), 但这是个错误写法
template <size_t N> struct Pow {
	double operator()(double x) const{
		return (N%2) ? (x*Pow<N/2>()(x) * Pow<N/2>()(x))
					 : (N ? Pow<N/2>()(x) * Pow<N/2>()(x))
					 : 1;
	};
};

如果模板Recursive有条件分支和三目运算,则必须保证所有的表达式都有效,编译器会查找所有的情况。而不仅仅是true的那个。

正确写法: 偏特化+默认模板参数->将分支判断移出函数内部

template <size_t N, bool N % 2> struct PowHelper{
	double operator()(double x) const { return Pow<N/2>()(x) * Pow<N/2>()(x);};
};
template <size_t N> struct PowHelper<N, false>{
	double operator()(double x) const { return x*Pow<N/2>()(x) * Pow<N/2>()(x);};
};
template <> struct PowHelper<1, true>{
	double operator()(double x) const { return x; };
};
template <> struct PowHelper<0, false>{
	double operator()(double x) const { return 1; };
};
// 封装起来以始终用default
template <size_t N> struct Pow{
	double operator()(double x) const { return Pow<N>()(x); };
}

3. 自适应代码 Self-Adaptive Code

(1). BitString, 从BitString中根据制定下标得到bit数值

template <typename T> BitString{
	T* data;
	enum { SHIFT = Log2<sizeof(N)>::value + 3};
	enum { MASK = T(1) << SHIFT -1 };
	bool getBit(size_t idx) const {
		T word = data[ idx >> SHITF ]; // get the word the bit index in
		T mask = T(1) << (i & MSAK);
		return word & mask;
	}
}

(2). deque, 双边队列
data[BlockSize*BlockNum],类似于BitString,Word为BlockIdx。

4. 类型操纵: Type Manipulate

(1). 检测Type类型:

template<class T> struct IsPtr{
	enum { value = 0 };
	typedef false_type type;
};
template<> struct IsPtr<T*>{
	enum { value = 1 };
	typedef true_type type;
};

(2). 类型转换:

//也可以利用Undefine来定义失败情况
template <class T> struct remove_ptr{
	typedef T type;
};
template <> struct remove_ptr<T*>{
	typedef T type;
}

5. 类型依赖代码(Type-dependent code)

(1). Sort by pointer/non-pointer Type

template<class T, bool Ptr> struct SortByType{....}
template<class T> struct SortByType<T, true>{....}
// for all type, 
// 1. is a (use derive)  
template<class T> struct SortContainer : public SortByType<T, is_ptr<T>::value> {....}
// 2. have a (use using or typedef)
template<class T> struct SortContainer{
	using Impl = SortByType<T, is_ptr<T>::value>;
	typedef SortByType<T, is_ptr<T>::value> type;
};

(2). Select to use internal sort or std::sort

template<class T> struct SortContainer: public Impl<T, has_sort<T>::value>{...};

6. 用SFINA来选择性编译:

(1). 判断类中是否有对应的成员函数:基本思路是偏特化两个函数(一个能匹配到成员函数,另一个匹配不到),两个函数采用为不同类型的返回值。最后通过返回值类型看出匹配的是哪个。

// example 1: before C++11
template<class T> struct hasSort{
	template<class U, size_t (U::*)()> struct SFINAE {};
	template<class U> static char test(SFINAE<U, &U::sort>*);
	template<class U> static int test(...);
	static constexpr bool Has = sizeof(test<T>(0)) == sizeof(char);
}
// example 2
template<class T> struct hasSort{
	template<class U> static auto test(void*) -> decltype(&U::sort, std::true_type());
	template<class U> static auto test(...) -> std::false_type;
	enum { value = sizeof(hasSort::test<T>(NULL)) == sizeof(std::true_type) };
};

(2). 判断是不是POD类型

template <class T> isClass{
	typedef char yes; typedef int no;
	template<class U> yes test(void* U::*); // is have member
	template<class U> no test(...);
	enum { value = sizeof(isClass::test<T>(NULL)) == sizeof(isClass::yes) };
};

(3). 检查一个expression是不是可以 compile

	template<class U> yes test(char*(a)[sizeof(EXPR)]); //用sizeof检查EXPR是否存在
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值