如何为 stl 之类的容器提供公共 const 迭代器和私有非 const 迭代器?

发布于 2024-08-25 18:13:20 字数 1574 浏览 4 评论 0原文

我有一个包含 std::list 的类,并希望为 const_iterator 提供公共 begin() 和 end() ,为普通迭代器提供私有 begin() 和 end() 。

但是,编译器看到私有版本并抱怨它是私有的,而不是使用公共 const 版本。

我知道 C++ 不会在返回类型上重载(在本例中为 const_iterator 和 iterator),因此它选择非 const 版本,因为我的对象不是 const。

在调用 begin() 之前将我的对象转换为 const 或不重载名称 begin 有没有办法实现此目的?

我认为这是人们之前已经解决过的已知模式,并且希望遵循通常如何解决的方法。

class myObject {
public:
  void doSomethingConst() const;
};

class myContainer {
public:
  typedef std::list<myObject>::const_iterator const_iterator;
private:
  typedef std::list<myObject>::iterator iterator;

public:
  const_iterator begin() const { return _data.begin(); }
  const_iterator end()   const { return _data.end();   }
  void reorder();
private:
  iterator begin() { return _data.begin(); }
  iterator end()   { return _data.end();   }
private:
  std::list<myObject> _data;
};

void myFunction(myContainer &container) {
  myContainer::const_iterator itr = container.begin();
  myContainer::const_iterator endItr = container.end();
  for (; itr != endItr; ++itr) {
    const myObject &item = *itr;
    item.doSomethingConst();
  }
  container.reorder(); // Do something non-const on container itself.
}

编译器的错误是这样的:

../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private
caller.cpp:2393: error: within this context
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private
caller.cpp:2394: error: within this context

谢谢。

——威廉

I have a class that includes a std::list and wish to provide public begin() and end() for const_iterator and private begin() and end() for just plain iterator.

However, the compiler is seeing the private version and complaining that it is private instead of using the public const version.

I understand that C++ will not overload on return type (in this case const_iterator and iterator) and thus it is choosing the non-const version since my object is not const.

Short of casting my object to const before calling begin() or not overloading the name begin is there a way to accomplish this?

I would think this is a known pattern that folks have solved before and would like to follow suit as to how this is typically solved.

class myObject {
public:
  void doSomethingConst() const;
};

class myContainer {
public:
  typedef std::list<myObject>::const_iterator const_iterator;
private:
  typedef std::list<myObject>::iterator iterator;

public:
  const_iterator begin() const { return _data.begin(); }
  const_iterator end()   const { return _data.end();   }
  void reorder();
private:
  iterator begin() { return _data.begin(); }
  iterator end()   { return _data.end();   }
private:
  std::list<myObject> _data;
};

void myFunction(myContainer &container) {
  myContainer::const_iterator itr = container.begin();
  myContainer::const_iterator endItr = container.end();
  for (; itr != endItr; ++itr) {
    const myObject &item = *itr;
    item.doSomethingConst();
  }
  container.reorder(); // Do something non-const on container itself.
}

The error from the compiler is something like this:

../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private
caller.cpp:2393: error: within this context
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private
caller.cpp:2394: error: within this context

Thanks.

-William

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千柳 2024-09-01 18:13:20

从 std::list 派生是个坏主意(它不是设计来派生的)。

使用 std::list 类型的成员变量。

class myContainer
{
  std::list<myObject>   m_data;
  public:

    typedef std::list<myObject>::const_iterator myContainer::const_iterator;
  private:
    typedef std::list<myObject>::iterator myContainer::iterator;

  public:

    myContainer::const_iterator begin() const
    {
      return m_data.begin();
    }

    myContainer::const_iterator end() const 
    {
      return m_data.end();
    }

  private:
    myContainer::iterator begin()
    {
      return m_data.begin();
    }

    myContainer::iterator end()
    {
      return m_data.end();
    }
};

Bad idea to derive from std::list (it is not designed to be derived from).

Use a member variable of type std::list.

class myContainer
{
  std::list<myObject>   m_data;
  public:

    typedef std::list<myObject>::const_iterator myContainer::const_iterator;
  private:
    typedef std::list<myObject>::iterator myContainer::iterator;

  public:

    myContainer::const_iterator begin() const
    {
      return m_data.begin();
    }

    myContainer::const_iterator end() const 
    {
      return m_data.end();
    }

  private:
    myContainer::iterator begin()
    {
      return m_data.begin();
    }

    myContainer::iterator end()
    {
      return m_data.end();
    }
};
弥繁 2024-09-01 18:13:20

我认为你唯一的选择是重命名私有方法(如果你首先需要它们)。

此外,我认为您应该重命名 typedef:

class MyContainer
{
public:
     typedef std::list<Object>::const_iterator iterator;
     typedef iterator const_iterator;

     const_iterator begin() const;
     const_iterator end() const;

private:
     typedef std::list<Object>::iterator _iterator;
     _iterator _begin();
     _iterator _end();
     ...
};

容器应该对 iteratorconst_iterator 进行 typedef。接受容器的非常量实例的通用函数可能期望使用迭代器 typedef - 即使它不会修改元素。 (例如 BOOST_FOREACH。)

只要 const 正确性就可以了,因为如果泛型函数实际上尝试修改对象,则真正的迭代器类型(是 const_iterator >) 不让。

作为测试,以下应该与您的容器一起编译:

int main()
{
    myContainer m;
    BOOST_FOREACH(const myObject& o, m) 
    {}
}

请注意,m 不是 const,但我们只是尝试获取对所包含类型的 const 引用,因此应该允许这样做。

I think your only option is to rename the private methods (if you need them in the first place).

In addition I believe you should rename the typedefs:

class MyContainer
{
public:
     typedef std::list<Object>::const_iterator iterator;
     typedef iterator const_iterator;

     const_iterator begin() const;
     const_iterator end() const;

private:
     typedef std::list<Object>::iterator _iterator;
     _iterator _begin();
     _iterator _end();
     ...
};

Containers are supposed to typedef both iterator and const_iterator. A generic function accepting a non-const instance of your container might expect to make use of the iterator typedef - even if it is not going to modify the elements. (For example BOOST_FOREACH.)

It will be fine as far as const correctness goes, because should the generic function actually try to modify the objects, the real iterator type (being a const_iterator) wouldn't let it.

As a test, the following should compile with your container:

int main()
{
    myContainer m;
    BOOST_FOREACH(const myObject& o, m) 
    {}
}

Note that m is not const, but we are only trying to obtain const references to the contained types, so this should be allowed.

可可 2024-09-01 18:13:20

您需要更改私有开始结束的名称。编译器不能仅通过返回类型来区分

这对我有用:注意 _begin _end 名称

#include <list>


class myObject {};

class myContainer : private std::list<myObject> {
public:
    typedef std::list<myObject>::const_iterator const_iterator;
private:
    typedef std::list<myObject>::iterator iterator;

public:
  myContainer::const_iterator begin() const {
    return std::list<myObject>::begin();
  }
  myContainer::const_iterator end() const {
    return std::list<myObject>::end();
  }
private:
  myContainer::iterator _begin() {
    return std::list<myObject>::begin();
  }
  myContainer::iterator _end() {
    return std::list<myObject>::end();
  }
};

void myFunction(myContainer &container) {
  myContainer::const_iterator aItr = container.begin();
  myContainer::const_iterator aEndItr = container.end();
  for (; aItr != aEndItr; ++aItr) {
    const myObject &item = *aItr;
    // Do something const on container's contents.
  }
}

int main(){
    myContainer m;
    myFunction(m);
}

You need to change the name of the private begin end. The compiler can't differentiate by only the return type

This works for me : note the _begin _end names

#include <list>


class myObject {};

class myContainer : private std::list<myObject> {
public:
    typedef std::list<myObject>::const_iterator const_iterator;
private:
    typedef std::list<myObject>::iterator iterator;

public:
  myContainer::const_iterator begin() const {
    return std::list<myObject>::begin();
  }
  myContainer::const_iterator end() const {
    return std::list<myObject>::end();
  }
private:
  myContainer::iterator _begin() {
    return std::list<myObject>::begin();
  }
  myContainer::iterator _end() {
    return std::list<myObject>::end();
  }
};

void myFunction(myContainer &container) {
  myContainer::const_iterator aItr = container.begin();
  myContainer::const_iterator aEndItr = container.end();
  for (; aItr != aEndItr; ++aItr) {
    const myObject &item = *aItr;
    // Do something const on container's contents.
  }
}

int main(){
    myContainer m;
    myFunction(m);
}
将军与妓 2024-09-01 18:13:20

您可能希望将方法 Myfunction 的签名更改为:

void myFunction(const myContainer &container) 

因为 const 方法只能在 const 对象上调用。当前发生的情况是您正在尝试调用一个非常量方法,在您的情况下该方法是私有的。

You might want to change the signature of your method Myfunction to this:

void myFunction(const myContainer &container) 

because a const method would be called on a const object only. What currently is happening is that you are trying to call a non-const method which in your case is private.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文