lundi 24 juillet 2017

Iterating uniformly over std::vector

I commonly face the situation where I introduce an abstract base class (call it Foo) to store instances of different child classes (call them Bar and Baz) in a container (e.g., std::vector<std::unique_ptr<Foo>>). For the sake of illustration, let me put these sample classes here:

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_;
};

If I implement a function to iterate over std::vector<std::unique_ptr<Foo>>, it looks like

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

But what if I also want to allow iterating over vectors of homogeneous type (e.g., std::vector<Bar>) without rewriting the whole function (or possible others, of similar type)? I see two obvious possibilities:

1) Implement functions

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;
}

and replace

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

by

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

2) Implement functions

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();
}

and replace

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

by

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

Option 1) seems like a general possibility to treat references of type Type & (or const Type &) and std::unique_ptr<Type> (or even Type * or const Type *) uniformly. However, I have not seen this being much used in production code. Is this a common pattern to avoid code duplication? Or are there better ways to handle this?

Aucun commentaire:

Enregistrer un commentaire