On Friday, 8 March 2024 at 06:03:51 UTC, Liam McGillivray wrote:
A problem I have is that the 3 classes Map, Tile, and Unit reference each-other. If I turn Map into a template, than it complains about the member variable of Unit declared as `Map map;` without arguments. I change this line to `Map!TileType map;` but this requires that Unit is also turned into a template.

If you don't want Unit to be a template, you can just have Map derive from a basic interface or abstract class. You can also have every relevant class share similar templates, you just need to remember to supply the template arguments everywhere. You'll need to think about how much interoperation you want between these classes. Does Unit really need to know what TileType map is using, or can it just trust that when it asks Map to move, Map will handle everything related to tile types? Generally it's best practice to have as much of the inner workings isolated as possible and just provide methods to access functionality. To ease some of the template argument!spaghetti, you could insert aliases into the classes via fully qualified symbol names. Another alternative, if everything is defined on one file, you could wrap everything in a single template, but I don't usually favor this strategy.

```d
//version=Interfaced;
version=AllTemplated;
//version=AllTemplatedAliases;
//version=OneTemplate;

version(Interfaced) {
        interface IMap {
                Unit addNewUnit();
        }
        class Map(TileType) : IMap {
                Unit[] units;
                Unit addNewUnit() {
                        auto unit = new Unit(this);
                        units ~= unit;
                        return unit;
                }
        }
        class Unit {
                IMap map;
                private this(IMap map) {
                        this.map = map;
                }
        }
        void main() {
                auto map = new Map!uint;
                auto unit = map.addNewUnit;
        }

} else version(AllTemplated) {
        class Map(TileType) {
                Unit!TileType[] units;
                auto addNewUnit() {
                        auto unit = new Unit!TileType(this);
                        units ~= unit;
                        return unit;
                }
        }
        class Unit(TileType) {
                Map!TileType map;
                private this(Map!TileType map) {
                        this.map = map;
                }
        }
        void main() {
                auto map = new Map!uint;
                auto unit = map.addNewUnit;
        }

} else version(AllTemplatedAliases) {
        class Map(TileType) {
                alias Unit = mymodule.Unit!TileType;
                Unit[] units;
                auto addNewUnit() {
                        auto unit = new Unit(this);
                        units ~= unit;
                        return unit;
                }
        }
        class Unit(TileType) {
                alias Map = mymodule.Map!TileType;
                Map map;
                private this(Map map) {
                        this.map = map;
                }
        }
        void main() {
                auto map = new Map!uint;
                auto unit = map.addNewUnit;
        }

} else version(OneTemplate) {
        template Map(TileType) {
                class Map {
                        Unit[] units;
                        auto addNewUnit() {
                                auto unit = new Unit(this);
                                units ~= unit;
                                return unit;
                        }
                }
                class Unit {
                        Map map;
                        private this(Map map) {
                                this.map = map;
                        }
                }
        }
        void main() {
                auto map = new Map!uint;
                auto unit = map.addNewUnit;
        }
}
```

If a given class doesn't really need to know what the template parameters are to the other class it's interacting with, I would avoid defining too many template types everywhere and just use interfaces or abstract parent classes.

After changing `class Unit` to `class Unit (TileType), it complains about the line `Unit* occupant;` in Tile.

Are you sure you need a pointer here? Class objects in D are already reference-type by default.
  • Can a D library ... Liam McGillivray via Digitalmars-d-learn
    • Re: Can a D... Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn
      • Re: Can... Liam McGillivray via Digitalmars-d-learn
        • Re:... Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn
          • ... Liam McGillivray via Digitalmars-d-learn
            • ... cc via Digitalmars-d-learn
              • ... Liam McGillivray via Digitalmars-d-learn
              • ... Liam McGillivray via Digitalmars-d-learn
                • ... Liam McGillivray via Digitalmars-d-learn
                • ... Liam McGillivray via Digitalmars-d-learn
                • ... cc via Digitalmars-d-learn
      • Re: Can... Liam McGillivray via Digitalmars-d-learn

Reply via email to