【问题标题】:std::iterator_traits divergence between libstdc++ and libc++libstdc++ 和 libc++ 之间的 std::iterator_traits 分歧
【发布时间】:2018-05-10 20:50:51
【问题描述】:

给定:

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, "");

出现错误:

错误:“std::__1::iterator_traits&lt;Iter&gt;”中没有名为“iterator_category”的成员 std::is_same&lt;std::iterator_traits&lt;Iter&gt;::iterator_category, Iter::iterator_category&gt;::value, "");

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

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

如果 Iterator 具有有效的 ([temp.deduct]) 成员类型 difference_­type、value_­type、pointer、reference 和 iterator_­category,则 iterator_­traits&lt;Iterator&gt; 应具有以下作为可公开访问的成员:

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&lt;Iterator&gt; 将没有上述任何名称的成员。

谁能解释这是否是一个实现错误,或者为什么我的期望是错误的?

【问题讨论】:

  • 在我解释标准时,唯一有效的 iterator_cathegory 类型是 input_iterator_tag、output_iterator_tag、forward_iterator_tag、bidirectional_iterator_tag 和 random_access_iterator_tag。如果 iterator_cathegory 有另一个值,则该迭代器没有有效的 iterator_cathegory 类型,因此该迭代器的 iterator_traits 应该没有任何指定的成员。

标签: c++ language-lawyer libc++ compiler-bug iterator-traits


【解决方案1】:

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

函数模板特化通常希望找出其迭代器参数的最具体类别,以便函数可以在编译时选择最有效的算法。为了促进这一点,该库引入了类别标记类,它们用作算法选择的编译时标记。它们是:input_­iterator_­tag、output_­iterator_­tag、forward_­iterator_­tag、bidirectional_­iterator_­tag 和 random_­acces_­iterator_­tag。对于Iterator 类型的每个迭代器,iterator_­traits&lt;Iterator&gt;​::​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&lt;Iter&gt;::iterator_category 不能给你回int。我建议拥有无效的迭代器类别只是违反了iterator_traits 的先决条件——这并不一定意味着库必须失败,但也不意味着失败是库错误。

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

【讨论】:

    猜你喜欢
    • 2012-02-18
    • 1970-01-01
    • 2017-01-03
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 2017-04-07
    相关资源
    最近更新 更多