使用不带容器的迭代器

发布于 2024-09-03 10:59:15 字数 660 浏览 3 评论 0原文

我正在混合一些 C 和 C++ 库,并且只有一个指针可用于在回调函数中执行一些工作。我需要做的就是迭代一个向量。下面是一个未经测试的简化示例:


bool call_back(void* data){
  done=...
  if (!done) cout << *data++ << endl;
  return done;
}

请注意,此函数位于 C++ 的 extern "C" 块中。 call_back 将被调用,直到返回 true。我希望它每次被调用时都能计算出下一个元素。 data 是一个指针,指向我可以从代码中其他地方传递的东西(上面示例中的迭代器,但可以是任何东西)。 data 中的某些内容可能会用于计算 done。我看到有两个明显的选项可以提供给 data

  1. data 指向我的向量。
  2. data 指向我的向量的迭代器。

如果没有可用的 .end() 方法,我就无法使用迭代器,对吧?我不能单独使用向量(除非我开始删除它的数据)。我可以用向量和迭代器创建一个结构体,但是有更好的方法吗?你会怎么办?

I am mixing some C and C++ libraries and have only a single pointer available to do some work in a callback function. All I need to do is iterate through a vector. Here's a simplified, untested example:


bool call_back(void* data){
  done=...
  if (!done) cout << *data++ << endl;
  return done;
}

Note that this function is in an extern "C" block in C++. call_back will be called until true is returned. I want it to cout the next element each time it's called. data is a pointer to something that I can pass from elsewhere in the code (an iterator in the above example, but can be anything). Something from data will likely be used to calculate done. I see two obvious options to give to data:

  1. Have data point to my vector.
  2. Have data point to an iterator of my vector.

I can't use an iterator without having the .end() method available, right? I can't use a vector alone (unless maybe I start removing its data). I could make a struct with both vector and iterator, but is there a better way? What would you do?

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

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

发布评论

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

评论(3

或十年 2024-09-10 10:59:15

为什么不让数据指向包含您需要的所有信息的结构。

关于旧的“C”风格回调的要点是 void* 可以指向任何对象。您的回调函数知道类型是什么,但它可以是任何类型。

typedef struct Plop
{
    std::vector<int>::iterator begin;
    std::vector<int>::iterator end;
} Plop;

bool call_back(void* data)
{
    // Or static_cast<> for the pedantic.
    // I like reinterpret_cast<> because it is a clue to humans that this is dangerious
    // and as long as the object was originally a Plop* pointer it is guaranteed to work.
    Plop*   info = reinterpret_cast<Plop*>(data);

    bool    done= info.begin == info.end;

    if (!done) cout << *data++ << endl;
    return done;
}

Why not have data point to a structure with all the information you need.

The point about the old "C" style callbacks is that a void* can point to any object. Your callback function knows what the type is, but it can be anything.

typedef struct Plop
{
    std::vector<int>::iterator begin;
    std::vector<int>::iterator end;
} Plop;

bool call_back(void* data)
{
    // Or static_cast<> for the pedantic.
    // I like reinterpret_cast<> because it is a clue to humans that this is dangerious
    // and as long as the object was originally a Plop* pointer it is guaranteed to work.
    Plop*   info = reinterpret_cast<Plop*>(data);

    bool    done= info.begin == info.end;

    if (!done) cout << *data++ << endl;
    return done;
}
荒人说梦 2024-09-10 10:59:15

如果没有 .end() 方法可用,我就无法使用迭代器,对吧?

不。您可以将迭代器与调用 .end() 函数的结果一起使用。您不需要继续调用 .end() 函数...所以如果您只存储两个迭代器,那么您就很成功了。

我不能单独使用向量(除非我开始删除它的数据)。

不仅如此,而且有了 std::size_t 索引,这就是您所需要的。

我可以使用向量和迭代器创建一个结构体,但是有更好的方法吗?你会做什么?

如果您不必担心支持其他容器类型,那么我会使用:

 template<typename T> struct CALLBACK_DATA
 {
      std::vector<T>* array;
      std::size_t index;
 };

如果您可能必须支持多种容器类型,那么我会使用:

 template<typename T> struct CALLBACK_DATA
 {
     typedef std::vector<T> container_type;
     typedef typename std::vector<T>::const_iterator const_iterator;
     const_iterator current;
     const_iterator end;
 };

所以,是的,我会传递向量和索引或一对迭代器,我将构造一个结构来保存数据。如果您想避免创建结构,那么您可以使用 std::pair,但我个人认为简单地创建一个自定义结构来保存此信息更具可读性。

I can't use an iterator without having the .end() method available, right?

No. You can use the iterator with the result of invoking the .end() function. You don't need to keep calling the .end() function... so if you just store both iterators, then you're golden.

I can't use a vector alone (unless maybe I start removing its data).

Not alone, but with a std::size_t index then that's all you would need.

I could make a struct with both vector and iterator, but is there a better way? What would you do?

If you don't have to worry about supporting other container types, then I would use:

 template<typename T> struct CALLBACK_DATA
 {
      std::vector<T>* array;
      std::size_t index;
 };

If you might have to support multiple container types, then I would use:

 template<typename T> struct CALLBACK_DATA
 {
     typedef std::vector<T> container_type;
     typedef typename std::vector<T>::const_iterator const_iterator;
     const_iterator current;
     const_iterator end;
 };

So, yeah, I would either pass the vector and an index or a pair of iterators, and I would construct a struct to hold the data. If you want to avoid creating a struct, then you could use std::pair, however I personally think it is more readable to simply create a custom struct to hold this information.

无风消散 2024-09-10 10:59:15

取消引用迭代器并将其值传递给call_back怎么样?然后在函数返回后增加它?

How about dereferencing the iterator and passing it's value to call_back? Then increment it after the function returns?

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