Effective C++: Item 48 -- Be aware of template metaprogramming (TMP)

模板元编程是一种在编译期间执行的C++程序技术,可以将工作从运行时转移到编译时,提高错误检测和运行效率。TMP通过递归模板实例化实现类似循环的效果,可用于确保单位正确性、优化矩阵操作和生成定制设计模式等。尽管语法不直观且工具支持不足,但对于某些程序员,尤其是库开发者,TMP是必不可少的工具。
摘要由CSDN通过智能技术生成

Definition

Template metaprogramming (TMP) is the process of writing template-based C++ programs that execute during compilation. Think about that for a minute: a template metaprogram is a program written in C++ that executes inside the C++ compiler. When a TMP program finishes running, its output — pieces of C++ source code instantiated from templates — is then compiled as usual.

TMP Greatest Strength

  1. it makes some things easy that would otherwise be hard or impossible.
  2. because template metaprograms execute during C++ compilation, they can shift work from runtime to compile-time.

One consequence is that some kinds of errors that are usually detected at runtime can be found during compilation. Another is that C++ programs making use of TMP can be more efficient in just about every way: smaller executables, shorter runtimes, lesser memory requirements. (However, a consequence of shifting work from runtime to compile-time is that compilation takes longer. Programs using TMP may take much longer to compile than their non-TMP counterparts.)

Trait Example in Item 47

void advance(std::list<int>::iterator& iter, int d) {
	if (typeid(std::iterator_traits<std::list<int>::iterator>::iterator_category) == 
		typeid(std::random_access_iterator_tag)) {
		iter += d; // compile error
	} else {
		if (d >= 0) { while (d--) ++iter; }
		else { while (d++) --iter; } 
	}
}

std::list<int>::iterator iter;
...
advance(iter, 10); 	// move iter 10 elements forward; 
					// won’t compile with above impl.

In this case, we’re trying to use += on a list<int>::iterator, but list<int>::iterator is a bidirectional iterator (see Item 47, so it doesn’t support +=. Even though, iter += d will not execute, the compiler will still check if the grammar is correct because compilers are obliged to make sure that all source code is valid, even if it’s not executed. Using TMP(Trait method mentioned in Item 47 can solve this problem.

Template metaprogramming (TMP)

TMP has been shown to be Turing-complete, which means that it is powerful enough to compute anything. Using TMP, you can declare variables, perform loops, write and call functions, etc.

Loop in TMP

TMP has no real looping construct, so the effect of loops is accomplished via recursion. Even the recursion isn’t the nor- mal kind, however, because TMP loops don’t involve recursive function calls, they involve recursive template instantiations.

Factorial Example

template<unsigned n> 	// general case: the value of
struct Factorial { 		// Factorial<n> is n times the value
						// of Factorial<n-1> 
	enum { value = n * Factorial<n-1>::value };
};
template<> 				// special case: the value of 
struct Factorial<0> { 	// Factorial<0> is 1
	enum{value=1}; 
};

Given this template metaprogram (really just the single template metafunction Factorial), you get the value of factorial(n) by referring to Factorial<n>::value.
The looping part of the code occurs where the template instantiation Factorial<n> references the template instantiation Factorial<n-1>. Like all good recursion, there’s a special case that causes the recursion to terminate. Here, it’s the template specialization Factorial<0>.
Each instantiation of the Factorial template is a struct, and each struct uses the enum hack (see Item 2) to declare a TMP variable named value. Since TMP uses recursive template instantiation in place of loops, each instantiation gets its own copy of value, and each copy has the proper value for its place in the “loop.”

What TMP can accomplish?

  • Ensuring dimensional unit correctness : In scientific and engineering applications, it’s essential that dimensional units (e.g., mass, distance, time, etc.) be combined correctly. Using TMP, it’s possible to ensure (during compilation) that all dimensional unit combinations in a program are correct, no matter how complex the calculations. (This is an example of how TMP can be used for early error detection.) One interesting aspect of this use of TMP is that fractional dimensional exponents can be supported. This requires that such fractions be reduced during compilation so that compilers can confirm, for example, that the unit t i m e 1 2 time^{\frac{1}{2}} time21 is the same as t i m e 4 8 time^{\frac{4}{8}} time84.
  • Optimizing matrix operations: Consider following code:
    typedef SquareMatrix<double, 10000> BigMatrix;
    BigMatrix m1, m2, m3, m4, m5; 	// create matrices and
    ...								// give them values
    BigMatrix result = m1 * m2 * m3 * m4 * m5;		// compute their product
    
    Using an advanced template technology related to TMP called expression templates, it’s possible to eliminate the temporaries and merge the loops, all without changing the syntax of the client code above. The resulting software uses less memory and runs dramatically faster.
  • Generating custom design pattern implementations: Design patterns like Strategy (see Item 35), Observer, Visitor, etc. can be implemented in many ways. Using a TMP-based technology called policy-based design, it’s possible to create templates representing independent design choices (“policies”) that can be combined in arbitrary ways to yield pattern implementations with custom behavior.
  • Generalized beyond the domain of programming artifacts like design patterns and smart pointers, this technology is a basis for what’s known as generative programming.

Conclusion

TMP is not for everybody. The syntax is unintuitive, and tool support is weak. However, TMP support is on the rise. It’s likely that the next version of C++ will provide explicit support for it, and TR1 already does (see Item 54). TMP will probably never be mainstream, but for some programmers — especially library developers — it’s almost certain to be a staple.

Things to Remember

  • Template metaprogramming can shift work from runtime to compile-time, thus enabling earlier error detection and higher runtime performance.
  • TMP can be used to generate custom code based on combinations of policy choices, and it can also be used to avoid generating code inappropriate for particular types.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值