簡體   English   中英

在std :: vector上均勻地迭代 <T> 和std :: vector <unique_ptr<T> &gt;

[英]Iterating uniformly over std::vector<T> and std::vector<unique_ptr<T>>

我通常遇到的情況是,我引入一個抽象基類(稱為Foo )以將不同子類(稱為BarBaz )的實例存儲在容器中(例如std::vector<std::unique_ptr<Foo>> )。 為了說明起見,讓我將這些示例類放在這里:

class Foo {
public:
    virtual int getId() const = 0;
};

class Bar : public Foo {
public:
    Bar(int id) : id_(id) {}
    int getId() const override { return id_; }
private:
    int id_;
};

class Baz : public Foo {
public:
    Baz(int id) : id_(id) {}
    int getId() const override { return id_; }
private:
    int id_;
};

如果我實現了一個迭代std::vector<std::unique_ptr<Foo>>的函數,它看起來像

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
    for (; first != last; ++first)
        std::cout << (*first)->getId() << std::endl;
}

但是,如果我還想允許遍歷同類類型的向量(例如std::vector<Bar> )而不重寫整個函數(或其他類似類型的函數)怎么辦? 我看到兩種明顯的可能性:

1)實現功能

template<class Type>
const Type & dereference(const Type &value) {
    return value;
}

template<class Type>
const Type & dereference(const std::unique_ptr<Type> &value) {
    return *value;
}

並更換

std::cout << (*first)->getId() << std::endl;

通過

std::cout << dereference(*first).getId() << std::endl;

2)實現功能

template<class Type>
int getId(const Type &value) {
    return value.getId();
}

template<class Type>
int getId(const std::unique_ptr<Type> &value) {
    return value->getId();
}

並更換

std::cout << (*first)->getId() << std::endl;

通過

std::cout << getId(*first) << std::endl;

選項1)似乎可以統一處理Type & (或const Type &const Type &std::unique_ptr<Type> (甚至Type *const Type * )的引用。 但是,我沒有看到它在生產代碼中使用得太多。 這是避免代碼重復的常見模式嗎? 還是有更好的方法來解決這個問題?

我會寫get_ptr<T>

如果失敗,則get_ptr<T*>返回nullptr。

如果傳遞了對可轉換為T*的對象的引用,它將返回它。

如果傳遞了對可轉換為T&的對象的引用,它將返回指向該對象的指針。

否則,如果傳遞了指針,則如果指針為null則返回null,如果指針不為null則返回get_ptr<T>(*ptr)

否則,如果x.get()返回一個指針,則返回get_ptr<T>(x.get())

現在printIds讀取:

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
  for (; first != last; ++first)
    std::cout << get_ptr<Foo>(*first)->getId() << std::endl;
}

請注意, get_ptr失敗的get_ptr在這里非常明顯。


如果您不想對T類型進行硬編碼,我們可以更進一步。

如果向get_obj_ptr傳遞了一個指向指針的指針,並且該指針不為null,則它將取消對該指針的引用並遞歸。 如果為null,則返回強制轉換為相同類型的nullptr。

如果傳遞了.get()返回其指針的類,則get_obj_ptr(x.get())將在get_obj_ptr(x.get())上遞歸。

否則,如果將指針傳遞給get_obj_ptr(x) ,則它將返回x

否則,如果將左值傳遞給get_obj_ptr(x) ,則它將返回std::addressof(x)

與您的代碼不同,它承認失敗的可能性。

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
  for (; first != last; ++first)
    auto* ptr = get_obj_ptr(*first);
    if (ptr)
      std::cout << ptr->getId() << std::endl;
    else
      std::cout << "null object" << std::endl;
}

通常,采用智能指針並假定它們永遠不會為空是一個壞主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM