標籤排程
在編譯時在函式之間進行選擇的一種簡單方法是將函式分派給一對過載的函式,這些函式將標記作為一個(通常是最後一個)引數。例如,要實現 std::advance()
,我們可以在迭代器類別上排程:
namespace details {
template <class RAIter, class Distance>
void advance(RAIter& it, Distance n, std::random_access_iterator_tag) {
it += n;
}
template <class BidirIter, class Distance>
void advance(BidirIter& it, Distance n, std::bidirectional_iterator_tag) {
if (n > 0) {
while (n--) ++it;
}
else {
while (n++) --it;
}
}
template <class InputIter, class Distance>
void advance(InputIter& it, Distance n, std::input_iterator_tag) {
while (n--) {
++it;
}
}
}
template <class Iter, class Distance>
void advance(Iter& it, Distance n) {
details::advance(it, n,
typename std::iterator_traits<Iter>::iterator_category{} );
}
過載的 details::advance
函式的 std::XY_iterator_tag
引數是未使用的函式引數。實際的實現並不重要(實際上它是完全空的)。它們的唯一目的是允許編譯器根據呼叫哪個標記類 details::advance
來選擇過載。
在這個例子中,advance
使用 iterator_traits<T>::iterator_category
元函式,它返回 iterator_tag
類之一,具體取決於 Iter
的實際型別。然後,iterator_category<Iter>::type
的預設構造物件允許編譯器選擇 details::advance
的不同過載之一。 (這個函式引數可能會被完全優化掉,因為它是一個空的 struct
的預設構造物件,從未使用過。)
標籤排程可以為你提供比使用 SFINAE 和 enable_if
的等效程式碼更容易閱讀的程式碼。
注意:雖然 C++ 17 的 if constexpr
可能特別簡化了 advance
的實現,但它不適合與標籤排程不同的開放式實現。