Question

I want to know how to achieve the following design. I have not put effort to follow the standard conventions in order to keep this dummy code to a minimum (eg, include guards). For arguments sake, I am using C++03, and only standard library components.

TL;DR: There is a cyclic dependency between my Restaurant and Recipe classes. I have a std::set<> of one pointers to object of Recipe in the Restaurant class, and vice-versa. I cannot #include one in the other, but due to the forward declaration, the compiler doesn't allow me to declare a custom comparator for the collections, as the value_types are still incomplete types at that point. Is there a way to achieve this?

I've included comments in code which explain my issue in more detail.

/*
 * restaurant.h
 */
#include <string>
#include <set>
/*
 * I cannot do this as recipe.h would need to include
 * restaurant.h, which restricts
 * me when I want to write a custom comparator.
 */
// #include "recipe.h"

class Recipe;

// I know this will not work as Recipe has not yet been declared.
struct RecipeComparator {
    bool operator() (const Recipe* lhs, const Recipe* rhs) { 
        return lhs->price() < rhs->price();
    }
};

class Restaurant {
    public:
        Restaurant(const std::string& name, float averagePrice);
        float averagePrice() { return m_averagePrice; }

    private:
        std::string m_name;
        float m_averagePrice;
        /*
         * I want to have the recipies sorted by their prices.
         * I cannot define RecipeComparator here as Restaurant
         * is an incomplete type till now. 
         */
        std::set< Recipe*, RecipeComparator > m_recipiesSorted;

        /*
         * This works, but does not do what I want.
         */
        std::set< Recipe* > m_recipies;
};

/*
 * recipe.h
 */
#include <string>
#include <set>
/*
 * I cannot do this as restaurant.h would need to include
 * recipe.h, so I need to forward declare, which restricts
 * me when I want to write a custom comparator.
 */
// #include "restaurant.h"

class Restaurant;

// I know this will not work as Restaurant has not yet been declared.
struct RestaurantComparator {
    bool operator() (const Restaurant* lhs, const Restaurant* rhs) { 
        return lhs->averagePrice() < rhs->averagePrice();
    }
};

class Recipe {
    public:
        Recipe(const std::string& name, float price);
        float price() { return m_price; }

    private:
        std::string m_name;
        float m_price;
        /*
         * This is what I want as I want to have the restaurants sorted
         * by their average prices.
         * I cannot define RestaurantComparator here as Restaurant
         * is an incomplete type till now. 
         */
        std::set< Restaurant*, RestaurantComparator > m_restaurantsSorted;

        /*
         * This works, but does not do what I want.
         */
        std::set< Restaurant* > m_restaurants;

};
Was it helpful?

Solution

One idea is to move your Comparator definitions to a .cpp source while keeping the declarations in the header. This way, restaurant.h and recipe.h will still only refer to each other by name and so a forward declare will still be enough.

// restaurant_recipe_comparators.h
// probably too long, give it a better name
struct RestaurantComparator
{
    bool operator() (const Restaurant *, const Restaurant *);
};

struct RecipeComparator
{
    bool operator() (const Recipe *, const Recipe *);
};

// restaurant_recipe_comparators.cpp
bool RestaurantComparator::operator() (const Restaurant* lhs, const Restaurant* rhs)
{ 
    return lhs->averagePrice() < rhs->averagePrice();
}


bool RecipeComparator::operator() (const Recipe* lhs, const Recipe* rhs)
{
    return lhs->price() < rhs->price();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top