用相同的代码循环遍历对象和指针

C++ Looping through objects and pointers with the same code

本文关键字:遍历 对象 指针 循环 代码      更新时间:2023-10-16

我有两个容器

set<Person>
vector<Person*>

是否有任何方法对以下转换lambda代码进行修改,以便任何一个容器都可以使用?

transform(container.begin(), container.end(), back_inserter(data),
          [](const Person* p) { return PairResults(p->getTime(), p->getName()); }
);

现在我只能让它作用在向量上

谢谢。

>>解决方案代码在这里

非常感谢Andrew在这方面的帮助!

您可以使用函数重载的一个小技巧来做到这一点:定义两个生成指向Person指针的函数,如下所示:

const Person* make_ptr(const Person* p) { return p; }
const Person* make_ptr(const Person& p) { return &p; }

下一个问题是统一lambda元素的类型:不幸的是,说[](auto p) {...}并让编译器为您选择PersonPerson*是不合法的。使用模板解决了这个问题:

template<typename T, typename R>
void xform(vector<T>& from, vector<R>& to) {
    transform(from.begin(), from.end(), back_inserter(to),
        [&](T &p) { return PairResults(make_ptr(p)->getTime(), make_ptr(p)->getName()); }
    );
}

现在一切工作-你可以调用xformPersonPerson*的容器,并得到正确的结果。

您可以使用代理对象接受指向Person或ref指向Person的指针,并为它们提供指针语义:

实例:http://ideone.com/Wk2VMx

#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <string>
struct Person {
    int age;
    std::string name;
};
class PersonProxy {
    public:
        PersonProxy(Person& p)
        : person(&p) {}
        PersonProxy(Person* p)
        : person(p) {}
        Person& operator*() { return *person; }
        Person* operator->() { return person; }
    private:
        Person* person;
};
int main()
{
    std::vector<Person> p1;
    p1.push_back(Person{42, "Bob"});
    Person bill{30, "Bill"};
    std::set<Person*> p2;
    p2.insert(&bill);
    std::vector<int> data;
    auto the_lambda = [](PersonProxy pp) {return pp->age;};
    std::transform(p1.begin(), p1.end(), std::back_inserter(data), the_lambda);
    std::transform(p2.begin(), p2.end(), std::back_inserter(data), the_lambda);
    for (int age : data)
    {
        std::cout << age << "n";
    }
}

另一种方法是使用函子而不是lambda,并定义operator()(Person&)operator()(Person*),但上面的方法是提供一种可以编写lambda的类型,并且可以使用从PersonPerson*进行隐式转换。

可能会像下面这样工作

   template <class T> struct MakePair {
      PairResults operator () (const T & p) {
         return PairResults(p.getTime(), p.getName());
      }
   };
   template <class T> struct MakePair<T*> {
      PairResults operator () (const T * p) {
         return PairResults(p->getTime(), p->getName());
      }
   };
   typedef decltype (* (container.begin ())) container_element_type;
   transform(container.begin(), container.end(), back_inserter(data),
          [] (const container_element_type & p) {
              return MakePair<container_element_type> {} (p);
          }
   );

在我看来,很难实现你所需要的,这表明你的代码中缺少一些抽象。

例如,谁负责处置vector中的堆分配对象?

考虑将容器的实现细节隐藏在具有良好定义接口的PersonContainer后面。