Search code examples
c++c++-templates

returning an std::optional<Type>& reference where Type is an abstract class


Background: I have a City template class that contains a 2D array that is populated by types that conform to ISpecies abstract class. The grid can be any size.
code:
ISpecies

class ISpecies {
public:
    ISpecies() = default;
    virtual ~ISpecies() = default;
    virtual std::string toString() = 0;
    virtual void move() = 0;
    virtual void spawn() = 0;
};

City

template<int H = 20, int W = 20>
class City {
protected:
    int h = H;
    int w = W;
    ISpecies* grid[H][W];


public:
    City() = default;
    City(City&) = delete;
    City(City&&) noexcept = default;
    City& operator=(const City&) = delete;
    City& operator=(City&&) noexcept = delete;
    ~City() = default;

    /** getters and setter methods */
    std::optional<ISpecies>& getOrganism(int x, int y);
    int getHeight() const;
    int getWidth() const;
    void setOrganism(ISpecies& species, int x, int y);

    /** stream output for printing out the city grid */
    template<int _h, int _w>
    friend std::ostream& operator<<(std::ostream& output, const City<_h, _w>& city);

};

Im having some problems with this getter function.
I have this getter where I am returning an optional reference of an abstract class:

template<int H, int W>
std::optional<ISpecies>& City<H, W>::getOrganism(int x, int y) {
    if((x < 0) || (x > this->w) || (y < 0) || (y > this->w)) {
        return std::nullopt;
    } else {
        return this->grid[y][x];
    }
};

However I am getting an error at std::nullopt where Non-const lvalue reference to type 'std::optional<ISpecies>' cannot bind to a value of unrelated type 'const nullopt_t'.

I am wondering if there is any way I can fix this? I have tried simply returning std::optional<ISpecies> however, I receive an error where I am returning an abstract class.

Thank you kindly for the help!


Solution

  • A minimal change to make the example well-formed would be to change the return type of getOrganism to std::optional<ISpecies*>.