template<typename IterT, typename DistT> void advance(IterT& iter, DistT d) { if (iter is a random access iterator) { iter += d; // use iterator arithmetic } // for random access iters else { if (d >= 0) { while (d--) ++iter; } // use iterative calls to else { while (d++) --iter; } // ++ or -- for other } // iterator categories } |
template<typename IterT, typename DistT> void advance(IterT& iter, DistT d) { if (typeid(typename std::iterator_traits<IterT>::iterator_category) == typeid(std::random_access_iterator_tag)) { iter += d; // use iterator arithmetic } // for random access iters else { if (d >= 0) { while (d--) ++iter; } // use iterative calls to else { while (d++) --iter; } // ++ or -- for other } // iterator categories } |
std::list<int>::iterator iter; ... advance(iter, 10); // move iter 10 elements forward; // won\'t compile with above impl. |
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; // error! } else { if (d >= 0) { while (d--) ++iter; } else { while (d++) --iter; } } } |
问题在突出显示的行,使用了 += 的那行。在当前情况下,我们试图在一个 list<int>::iterator 上使用 +=,但是 list<int>::iterator 是一个 bidirectional iterator(双向迭代器)(参见《C++箴言:为类型信息使用特征类》),所以它不支持 +=。只有 random access iterators(随机访问迭代器)才支持 +=。此时,我们知道我们永远也不会试图执行那个 += 行,因为那个 typeid 检测对于 list<int>::iterators 永远不成立,但是编译器被责成确保所有源代码是正确的,即使它不被执行,而当 iter 不是一个 random access iterator(随机访问迭代器)时 \"iter += d\" 是不正确的。traits-based(基于 traits)的 TMP 解决方案与此对比,那里针对不同类型的代码被分离到单独的函数中,其中每一个都只使用了可用于它所针对的类型的操作。
TMP 已经被证明是 Turing-complete(图灵完备)的,这意味着它强大得足以计算任何东西。使用 TMP,你可以声明变量,执行循环,编写和调用函数,等等。但是这些结构看起来与其在“常规”C++ 中的样子非常不同。例如,《C++箴言:为类型信息使用特征类》展示了 if...else 条件在 TMP 中是如何通过 templates(模板)和 template specializations(模板特化)被表达的。但那是 assembly-level(汇编层次)的 TMP。针对 TMP 的库提供了一种更高层次的语法,虽然还不至于让你把它误认为是“常规”C++。
为了一窥其它东西在 TMP 中如何工作,让我们来看看 loops(循环)。TMP 中没有真正的 looping construct(循环结构),因此 loops(循环)的效果是通过 recursion(递归)完成的。(如果你对 recursion(递归)感到不舒服,在你斗胆进入 TMP 之前一定要解决它。TMP 很大程度上是一个 functional language(函数性语言),而 recursion(递归)之于 functional language(函数性语言)就像电视之于美国流行文化:是密不可分的。)然而,甚至 recursion(递归)都不是常规样式的,因为 TMP loops 不涉及 recursive function calls(递归函数调用),它们涉及 recursive template instantiations(递归模板实例化)。