如何重载模板函数以匹配特定容器

How to overload a template function to match specific containers?

本文关键字:函数 何重载 重载      更新时间:2023-10-16

我有以下函数来检索容器的n元素 - O(n)

template<typename Container>
const typename Container::value_type& getNthElement(const Container& container, size_t n) {
    auto itr = cbegin(container);
    for (auto i = 0u; i < n; ++i) {
        ++itr;
    }
    return *itr;
}

对于vectors我有这种过载 - O(1)

template<typename T>
T getNthElement(const vector<T>& container, size_t n) {
    return container[n];
}

现在,如果我想使用 deque(它也具有O(1)实现),第一个模板函数将使用O(n)实现调用。

如何使第二个过载功能适应vectorsdeques的工作?
我的问题取自这篇文章。

简单的方法是基于迭代器类别进行标记,即如下所示:

template <typename It>
typename std::iterator_traits<It>::value_type
nth_element(It begin, It end, std::size_t n, std::input_iterator_tag) {
    for (std::size_t i(0); it != end && i != n; ++i) {
        ++i;
    }
    return it != end? *it: throw std::runtime_error("out of range");
}
template <typename It>
typename std::iterator_traits<It>::value_type
nth_element(It begin, It end, std::size_t n, std::random_access_iterator_tag) {
    return n < std::size_t(end - begin)? it[n]: std::runtime_error("out of range");
}
template <typename C>
typename C::value_type
nth_element(Container const& c, std::size_t n) {
    return nth_element(c.begin(), c.end(), n,
                       typename std::iterator_traits<C>::iterator_category());
}

如果不是因为n可能太大,你实际上可以让std::advance()做到这一点:

template <typename C>
typename C::value_type
nth_element(Container const& c, std::size_t n) {
    auto it = c.begin();
    std::advance(it, n);
    return *it;
}

借助 C++11 扩展的 SFINAE,您可以嗅出即使没有性状,此功能是否可用。