4

鉴于:

struct Iter {
    using value_type = int;
    using difference_type = int;
    using reference = int;
    using pointer = int;
    using iterator_category = int;
};

以下内容适用于 libstc++,但无法针对 libc++ 5.0.0 进行编译:

#include <iterator>
#include <type_traits>
static_assert(
    std::is_same<
        std::iterator_traits<Iter>::iterator_category,
        Iter::iterator_category
    >::value, "");

出现错误:

错误: ' ' 中没有名为 ' iterator_category' 的std::__1::iterator_traits<Iter>成员 std::is_same<std::iterator_traits<Iter>::iterator_category, Iter::iterator_category>::value, "");

如果Iter::iterator_category是标准输入类别之一,则静态断言成功,例如std::input_iterator_tag

恕我直言,它不应该失败,因为 C++ 草案在[iterator.traits]#2中声明:

如果 Iterator 具有有效的 ( [temp.deduct] ) 成员类型difference_­typevalue_­typepointerreferenceiterator_­categoryiterator_­traits<Iterator>则应具有以下作为可公开访问的成员:

using difference_type   = typename Iterator::difference_type;
using value_type        = typename Iterator::value_type;
using pointer           = typename Iterator::pointer;
using reference         = typename Iterator::reference;
using iterator_category = typename Iterator::iterator_category;

否则,iterator_­traits<Iterator>不得有上述任何名称的成员。

任何人都可以解释这是否是一个实现错误,或者为什么我的期望是错误的?

4

1 回答 1

2

我们也有,在[std.iterator.tags]

函数模板特化通常需要找出其迭代器参数的最具体类别是什么,以便函数可以在编译时选择最有效的算法。为了促进这一点,该库引入了类别标记类,它们用作算法选择的编译时标记。它们是:input_­iterator_­tagoutput_­iterator_­tagforward_­iterator_­tagbidirectional_­iterator_­tagrandom_­acces_­iterator_­tag对于每个类型的迭代器Iteratoriterator_­traits<Iterator>​::​iterator_­category应定义为描述迭代器行为的最具体的类别标签。

namespace std {
  struct input_iterator_tag { };
  struct output_iterator_tag { };
  struct forward_iterator_tag: public input_iterator_tag { };
  struct bidirectional_iterator_tag: public forward_iterator_tag { };
  struct random_access_iterator_tag: public bidirectional_iterator_tag { };
}

int不是这些标签之一,所以iterator_traits<Iter>::iterator_category不能还给你int。我建议拥有一个无效的迭代器类别只是违反了先决条件iterator_traits——这并不一定意味着库必须失败,但这也不意味着失败是库错误。

但是,这些先决条件在 [iterators] 中没有像在库部分的其他部分中那样明确说明。所以我倾向于建议这两个库都是正确的,但 libc++ 不定义任何成员别名的iterator_traits<Iter>方法可能更好。

于 2017-11-27T16:22:26.633 回答