检查模板形参是否有随机访问迭代器

Checking if a template parameter have Random Access Iterator or not

本文关键字:随机 访问 迭代器 是否 形参 检查      更新时间:2023-10-16

我对元编程完全陌生,并且我有一些问题。我想写一个容器,它有不同的内部表示,如果传递的ContainerRandom Access Iterator,使用不同的算法。然而,我不知道如何检查它。

更新:现在我正在尝试以下内容:

template <typename Container>
struct HaveRandomAccessIterator
{
    typedef char yes[1];
    typedef char no[2];
    template <typename C>
    static yes& test (typename std::random_access_iterator_tag*);
    template <typename>
    static no& test (...);
    static const bool value = sizeof(test<std::iterator_traits<typename Container::iterator*>::iterator_category*>(0)) == sizeof(yes);
};

然而,它给我std::list的真值,我得到编译错误,因为在这种情况下,我使用了操作符[]

谁能告诉我怎样才能正确地检查它?

您的HaveRandomAccessIterator模板过于复杂,有更简单的方法来实现相同的结果。

根据迭代器类型改变算法的一种标准方法是tag-dispatch:

//First, a helper type alias
template<typename Container>
using IteratorCategoryOf =
    typename std::iterator_traits<typename Container::iterator>::iterator_category;
template<typename Container>
void algorithm(Container &c, std::forward_iterator_tag) {
    //do generic version of algorithm
}
template<typename Container>
void algorithm(Container &c, std::random_access_iterator_tag) {
    //do random-access version of algorithm
}
template<typename Container>
void algorithm(Container &c) {
    algorithm(
        c,
        IteratorCategoryOf<Container>());
}

或者,您可以通过std::enable_if使用SFINAE。我怀疑这是你的目标,但HaveRandomAccessIterator可以用std::is_base_of来写,这要简单得多:

template<typename Container>
using HaveRandomAccessIterator =
    std::is_base_of<
        std::random_access_iterator_tag,
        IteratorCategoryOf<Container>>;
template<
    typename Container,
    typename std::enable_if<!HaveRandomAccessIterator<Container>::value>::type * = nullptr>
void algorithm(Container &c) {
    //do generic version of algorithm
}
template<
    typename Container,
    typename std::enable_if<HaveRandomAccessIterator<Container>::value>::type * = nullptr>
void algorithm(Container &c) {
    //do random-access version of algorithm
}

如果需要c++ 03兼容性,您可以使用继承而不是类型混叠,以及std::enable_ifstd::is_base_of的boost对应项。

应该是:

static yes& test (typename std::iterator_traits<typename C::iterator*>::random_access_iterator_tag*);

SFINAE是这样工作的。

同时,我发现下面的语句更优雅:

struct yes{};
struct no {};
enum { value = std::is_same<yes, [test-here]>::value };