Seeking proper system for pairing types My code below ensures that only land animals can be a "representatives" for Land while only ocean animals can be representatives for Ocean, and so forth for Air, Underground, etc...  Just want some feedback about whether this system I've come up with is any good or if there is a better one.  Note:  I'm using structs instead of classes to keep it simple.

#include &lt;iostream&gt;
#include &lt;list&gt;

struct IAnimal { virtual ~IAnimal() = default; };

template &lt;typename T&gt;
struct Animal : virtual IAnimal {};  // Animal&lt;T&gt; can only be pair with T, where T is derived from Place.

struct Place {
    IAnimal* representative;
    virtual bool setRepresentative (IAnimal* a) {
        representative = a;  std::cout &lt;&lt; "Done.\n";  return true;
    }
    virtual bool canUse (const IAnimal*) const = 0;
};

template &lt;typename Derived&gt;
struct PlaceCRTP : Place {
    virtual bool setRepresentative (IAnimal* a) override {
        if (canUse(a))
            return Place::setRepresentative(a);
        std::cout &lt;&lt; "Cannot be done.\n";
        return false;
    }
    virtual bool canUse (const IAnimal* a) const override {
        return dynamic_cast&lt;const Animal&lt;Derived&gt;*&gt;(a) != nullptr;
    }
};

struct Land : PlaceCRTP&lt;Land&gt; {};
struct Ocean : PlaceCRTP&lt;Ocean&gt; {};

struct Elephant : Animal&lt;Land&gt; {};
struct Moose : Animal&lt;Land&gt; {};
struct Deer : Animal&lt;Land&gt; {};
struct Whale : Animal&lt;Ocean&gt; {};
struct Shark : Animal&lt;Ocean&gt; {};
struct Crab : Animal&lt;Ocean&gt;, Animal&lt;Land&gt; {};  // Note: Crab can represent Ocean or Land!

int main() {
    Land land;
    Elephant elephant;
    Whale whale;
    land.setRepresentative(&amp;elephant);  // Done.
    land.setRepresentative(&amp;whale);  // Cannot be done.

    std::list&lt;IAnimal*&gt; allAnimals, landCandidates;
    for (int i = 0; i &lt; 10; i++) {
        allAnimals.push_back (new Elephant);
        allAnimals.push_back (new Whale);
        allAnimals.push_back (new Moose);
        allAnimals.push_back (new Shark);
        allAnimals.push_back (new Crab);
    }
    for (IAnimal* a : allAnimals)
        if (land.canUse(a))
            landCandidates.push_back(a);
    std::cout &lt;&lt; allAnimals.size() &lt;&lt; std::endl;  // 50
    std::cout &lt;&lt; landCandidates.size() &lt;&lt; std::endl;  // 30 (10 Elephants, 10 Moose, 10 Crabs)
}


One drawback I can think of right away, is that the repeated dynamic casts cost performance, but looking up a map might be slower.
The design of Place.canUse(Animal) suggests that places use animals. 
But in reality it's the other way around.
The question is not if land can use a whale,
but if a whale can "use" land.
I suggest to invert the design to Animal.canUse(Place) (or possibly even canInhabit).

If performance is important,
then you can add in Animal one method for each Place type,
for example canUseLand, canUseOcean.
After all, do you seriously need to consider future expansion of place types?
It's the animal kingdom that's likely to grow.
And the canUseX methods only need to be implemented in higher level classes,
the vast majority will be happy to inherit.