Based on "tag dispatching" pattern, I've written a solution to my question:
// Using "= delete" on un-supported categories to get concise compile-time error information
template<typename Iter> void _foo(Iter first, Iter last, std::bidirectional_iterator_tag) = delete;
template<typename RandomIter>
void _foo(RandomIter first, RandomIter last, std::random_access_iterator_tag)
{ ... }
template<class Iter>
void foo(Iter first, Iter last)
{
typename std::iterator_traits<Iter>::iterator_category category;
_foo(first, last, category);
}
It works now. Please leave comment if it has bug or need improvement. Thanks.