【问题标题】:Checking if a template parameter have Random Access Iterator or not [duplicate]检查模板参数是否具有随机访问迭代器 [重复]
【发布时间】:2014-07-13 22:07:44
【问题描述】:

我对元编程完全陌生,但我遇到了一些问题。 我想编写一个具有不同内部表示的容器,如果传递的Container 具有Random 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 的真正价值,我得到了编译错误,因为在那种情况下我使用 operator[]

谁能解释我如何正确检查它?

【问题讨论】:

    标签: c++ templates iterator template-meta-programming


    【解决方案1】:

    您的HaveRandomAccessIterator 模板过于复杂,有更简单的方法可以达到相同的效果。

    根据迭代器类型更改算法的一种标准方法是标记调度:

    //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 兼容性,您可以使用继承而不是类型别名,而 boost 对应于 std::enable_ifstd::is_base_of

    【讨论】:

      【解决方案2】:

      应该是:

      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 };
      

      【讨论】:

      • 哇,我犯了这么愚蠢的错误,非常感谢!但是,它总是具有错误值,即使对于 std::vector 也是如此。
      • iterator_traitsiterator_category 成员 typedef。 random_access_iterator_tragstd 命名空间中的标签。
      • 好吧,我真的不明白我应该如何解决这个问题。现在我正在尝试这个:static yes&amp; test (typename std::random_access_iterator_tag*); static const bool value = sizeof(test&lt;std::iterator_traits&lt;typename Container::iterator*&gt;::iterator_category*&gt;(0)) == sizeof(yes); 但是它为列表提供了真正的价值,并且当我想使用 operator[] 时会给出编译错误
      猜你喜欢
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2022-11-14
      相关资源
      最近更新 更多