【问题标题】:How to make idempotent taking a reference to a dereference of an iterator如何使对迭代器的取消引用的引用具有幂等性
【发布时间】:2016-09-02 11:08:28
【问题描述】:

下面的代码(-std=c++11)根据“幼稚”的观点应该可以工作。 相反,它没有(应该知道并理解为什么它没有)。 修改代码(重载&)以使其按照“天真”视图运行的最短方法是什么? 在创建 stl 对象期间不应该将其作为一个选项(不要写太多)吗?

#include <iostream>
#include <vector>

int main(int argc, char **argv)
{   std::vector<int> A{10,20,30};
    auto i=A.begin();
    auto j=&*i;
    std::cout<<"i==j gives "<<(i==j)<<std::endl;
    return 0;
}

【问题讨论】:

  • 对我来说这看起来像一个XY problem。你的实际目标是什么?您希望该行为在什么时候有效?
  • 是的。 为什么你想打破“转换为实际地址”运算符(&*)。
  • 解释一下你所说的“工作”是什么意思
  • @MartinBonner 我的意思是我想让 &*i 等价于 i
  • 是的,但这意味着 &* 的结果不会是原始指针——我认为这是“破坏”“原始地址运算符”。 (现在有一个标准函数可以返回原始地址运算符,即使存在 operator &amp; - 但我认为停止 &* 工作是非常糟糕的。

标签: c++ reference iterator dereference


【解决方案1】:

这应该行不通——甚至“不符合‘天真的’视图”。尽管每个指针都是一个迭代器,但反过来不一定正确。你为什么期望它行得通?

它可以在两种情况下工作:

  1. std::vector&lt;T&gt; 实现的iterator 实际上是T*。然后您的代码将在 decltype(i) == int*decltype(j) == int*) 之后运行。某些编译器可能就是这种情况,但如果您的编译器确实如此,您甚至不应该依赖它。

  2. 取消引用运算符不返回 T 类型的对象,而是返回可转换为 T 并具有重载的 operator&amp; 的对象,从而返回迭代器。出于很好的原因,情况并非如此。

您可以 - 正如其他人所建议的那样 - 重载 operator== 以检查两个间接(指针和迭代器)是否引用同一个对象,但我怀疑您希望运算符的地址将迭代器返回给您,如果迭代器不是指针,因为存储在向量中的对象类型没有向量/迭代器等概念。

问题不在于相等运算符,我需要定义解引用运算符以提供迭代器

你不能。有问题的取消引用运算符是std::vector&lt;int&gt;::iterator,它是标准库的一部分,您可以(也不应该)操纵它。


请注意,由于 C++11 中的 std::vector&lt;T, A&gt;

  • value_typeT
  • referenceT&amp;

此外,以下是正确的:

  • 所有输入迭代器 i支持*i,它给出了T类型的值,即值该迭代器的类型
  • std::vector&lt;T&gt; 的迭代器需要将T 作为其值类型
  • std::vector&lt;T&gt; 的迭代器是一个输入迭代器

【讨论】:

  • 模板 std::vector 除了第一个参数外还有很多参数。这些都是可用的,以便给予。所以我正在寻找任何可能提供所请求行为的解决方案。
  • @GeorgeKourtis:正如我在下面问你的问题:你为什么要这样做? ...一个std:vector 模板参数只是元素类型,另一个是关于分配的。第二个不会影响您打算更改的行为。您可以通过将您的实际类型包装在一个类型中来解决这个问题,该类型存储指向它所存储的向量的指针,并且一旦初始化使用operator&amp; 为您提供正确的迭代器,但这不会很有用。
  • 关于分配的成员,指定了很多东西,如value_type、指针、引用,我想这样可以获得结果。
  • @GeorgeKourtis:不,不是,不是。
【解决方案2】:

问题无法解决。无法解决的原因有三个

第一个问题

您需要重载的operator &amp; 是向量元素类型的operator &amp;。你不能为任意类型重载operator &amp;,尤其是你不能为内置类型重载它(比如你的例子中的int)。

第二个问题

大概您希望它适用于std::vectorstd::array 和内置数组?也可能是std::liststd::deque 等?你不能。每个包含的迭代器都会不同(实际上:在 理论上,其中一些可以共享迭代器,但我不知道它们在哪里有任何标准库。)

第三个问题

如果您准备接受这仅适用于std::vector&lt;MyType&gt;,那么您可以重载MyType::operator &amp; - 但您仍然无法确定MyType 对象存在于哪个std::vector&lt;MyType&gt;(并且您需要获取迭代器)。

【讨论】:

  • 关于第一个问题,方法不准确。应该重载的是 operator & 用于对 int 的引用(作为引用很重要,因为如果不是很明显,我们就无法获得迭代器)。关于 & 内置类型的重载,我想你是正确的,所以应该修改问题,而不是 int 一个结构,以便能够做到这一点。
  • 关于第二个问题,对对象的引用可以很容易地转换为随机访问容器的迭代器。取而代之的是非随机访问,操作很慢。
  • 关于第三个问题,你是对的。只有在引用和迭代器都实现为指针的情况下,我们才可以将引用转换为迭代器。另一方面,通常的实现就是这种情况。
  • 但是还有一点我其实不太明白:迭代器可以定义值的类型,指向值的指针的类型,以及参考。所以可能以不同的方式定义它们仍然可以获得预期的效果。
  • 我们还可以重载reference_type的赋值运算符。但究竟如何?
【解决方案3】:

首先,在您的代码中,sn-p i 减去 std::vector&lt;int&gt;::iteratorj 减去 int*。编译器不知道如何比较 std::vector&lt;int&gt;::iteratorint*

为了解决这个问题,您可以提供一个重载的operator==,它会按以下方式将向量迭代器与向量值类型指针进行比较:

template<typename T>
bool operator==(typename std::vector<T>::iterator it, T *i) {
  return &(*it) == i;
}

template<typename T>
bool operator==(T *i, typename std::vector<T>::iterator it) {
  return it == i;
}

Live Demo

【讨论】:

  • 这比较元素的地址是否相等,而不是元素本身。我在下面借用了你的想法,但取消了指针和迭代器的引用。希望礼仪没问题。
  • @T33C 也许 OP 想要比较地址而不是值,(如果向量包含相同值的多个副本,这会有所不同)
  • 也许......但奇怪的事情尤其是对于一个容器,当添加更多元素并需要调整大小时,它可能会重新定位其元素。
猜你喜欢
  • 2015-09-26
  • 1970-01-01
  • 2012-11-01
  • 2015-01-13
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多