【问题标题】:Why can't I get value_type from iterator_traits?为什么我不能从 iterator_traits 获取 value_type?
【发布时间】:2019-06-04 09:59:51
【问题描述】:

我正在这样做:

const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
const auto foo = cbegin(arr);
const typename iterator_traits<decltype(foo)>::value_type bar = 1;

我本来希望bar 具有int 类型。但是我得到了一个错误:

错误 C2039:value_type:不是std::iterator_traits&lt;_Ty *const &gt; 的成员

这是const 的问题,我需要去掉它吗?

【问题讨论】:

  • 我通常为此使用std::decay。不过,我不愿意将此作为答案发布,因为我并不完全理解为什么它似乎可以解决所有这些问题。所以它可能不是正确的解决方案。你会写const typename std::iterator_traits&lt;std::decay_t&lt;decltype(foo)&gt;&gt;::value_type bar = 1;
  • @FrançoisAndrieux 是的,我希望我可以为vector 或数组工作...decay 仍然可以在那里工作...所以也许这是最好的?
  • @JonathanMee 它也适用于非指针迭代器类型。以我的经验,它每次都能解决这类问题并且神奇地起作用。尽管如此,它对我来说似乎很神奇的事实让我对推荐它感到紧张。
  • @FantasticMrFox 该更改旨在处理volatile T*。它不会为 T* const 添加专业化。

标签: c++ types iterator typename iterator-traits


【解决方案1】:

这里的问题在于行

const auto foo = cbegin(arr);

cbegin(arr) 将返回一个 int const *(指向 const int 的指针),因此将 const 应用于 const auto foo 意味着 foo 是一个 int const * const(指向 const int 的指针)

std::iterator_traits 仅专用于 T*T const*,因此给它一个 T* const 失败,因为没有有效的专业化。

您可以通过删除 bar 声明中的常量来解决此问题

const typename std::iterator_traits<std::remove_cv_t<decltype(foo)>>::value_type

或者您可以将foo 更改为

auto foo = std::cbegin(arr);

如果你可以接受它不是const

【讨论】:

  • 它通过削弱foo的类型契约来“修复”问题。这不是一个好的解决方案:foo 应该 声明为const。不要删除它!
  • 我同意@KonradRudolph 的观点,最好将foo 保留为const。我觉得最好改用 iterator_traits 的模板参数。
  • @KonradRudolph 我已经更新了答案,但这真的取决于 OP 想要用它做什么。您通常可以从容器中重新分配 const_iterators,因此删除 const 使其行为相同。
【解决方案2】:

确实const 有问题,你基本上这样做:

std::iterator_traits<const int* const>::value_type // incorrect due to the last const

您可以通过将其更改为来修复它

std::iterator_traits<const int*>::value_type // Correct

您可以为此使用std::decaystd::remove_cv

const typename std::iterator_traits<std::remove_cv_t<decltype(foo)>>::value_type

(或从foo 中删除const,如果相关)。

【讨论】:

  • 值得指出@FantasticMrFox's comment remove_cv_t 在 C++20 中自动发生。所以我想说这确实是首选的解决方案。
【解决方案3】:

声明一个 const 限定的迭代器 const auto foo = cbegin(arr); 是有问题的。不能应用 operator++() 的迭代器有什么用?此外,Iterator 要求要求 int const *const 类型为 Copy Assignable;因此,变量 foo 不满足 Iterator 要求。所以严格来说,foo 不是 Iterator

【讨论】:

  • 我的意思是next 仍然可以正常工作吗?这与const char* const 的论点相同,但在某些情况下,这会编译成比const char* 更优化的代码
  • @JonathanMee std::next 需要一个满足 LegacyInputIterator 的参数,这要求类型通过 LegacyIterator 要求是 CopyAssignable。 Iterator 类型本质上不是 const 可限定的。
  • @JulienVillrmure-Fréchette 我从您的陈述中假设:“迭代器类型本质上不是 const 可限定的。”您的意思是修改常量迭代器的唯一方法是对其副本进行操作?并且通常迭代器的重点是修改?
  • 有意义的迭代器常量的简单示例:范围的结尾。虽然我也没有看到 const cbegin 的用例...
猜你喜欢
  • 2017-09-06
  • 1970-01-01
  • 1970-01-01
  • 2020-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多