advance 的效能難題advance(iter, d) 將迭代器移動 d 步。概念上是 iter += d,但只有 Random Access Iterator 支援 +=。弱一級的迭代器 (Bidirectional、Forward、Input) 必須迴圈呼叫 ++/--,線性時間。如何在編譯期依迭代器類型選擇最佳實作?
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
繼承關係反映能力層級:Forward 是 Input,Bidirectional 是 Forward,Random Access 是 Bidirectional。
iterator_traitsTraits 非關鍵字,而是慣例與技術:以結構體模板儲存類型資訊,支援內建型別 (指標) 與用戶定義型別。
class deque {
public:
class iterator {
public:
typedef random_access_iterator_tag iterator_category;
// ...
};
};
template<typename IterT>
struct iterator_traits<IterT*> {
typedef random_access_iterator_tag iterator_category;
// ...
};
template<typename IterT>
struct iterator_traits {
typedef typename IterT::iterator_category iterator_category;
// ...
};
利用函式多載,編譯器依傳入的 tag 型別選擇正確實作:
// Random Access 版本
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::random_access_iterator_tag) {
iter += d;
}
// Bidirectional 版本
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag) {
if (d >= 0) while (d--) ++iter; else while (d++) --iter;
}
// Input/Forward 版本 (Forward 繼承 Input,自動複用)
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::input_iterator_tag) {
if (d < 0) throw std::out_of_range("Negative distance");
while (d--) ++iter;
}
// 主介面
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
doAdvance(iter, d,
typename std::iterator_traits<IterT>::iterator_category());
}
Tag 物件 iterator_category() 僅作為多載解析的「鑰匙」,不佔用儲存空間。
iterator_category)。char_traits:字元型別特性。numeric_limits:數值型別限制 (min/max/epsilon)。is_fundamental、is_array、is_base_of 等。if...else 型別分派,零執行期開銷。