Declaring template functions in a C ++ interface?

To demonstrate, imagine that I have some classes of animals, each of which is derived from the class of "animals", each of which "knows" what type they are, and each of which has its own unique ability:

enum class animal_type { antelope, bear, cat };

class animal
{
};

class antelope : public animal
{
public:
    static const animal_type type = animal_type::antelope;
    void run() { std::cout << "antelope runs\n"; };
};

class bear : public animal
{
public:
    static const animal_type type = animal_type::bear;
    void roar() { std::cout << "bear roars\n"; };
};

class cat : public animal
{
public:
    static const animal_type type = animal_type::cat;
    void meow() { std::cout << "cat meows\n"; };
};

Now I want to be able to get animals by their type:

class animal_getter
{
public:
    animal& get(animal_type t)
    {
        static antelope s_antelope;
        static bear s_bear;
        static cat s_cat;

        switch (t)
        {
            case animal_type::antelope:
                return s_antelope;

            case animal_type::bear:
                return s_bear;

            case animal_type::cat:
                return s_cat;
        }
    }
};

And finally, it would be nice to get the real type of animal back to make the call syntax more enjoyable:

template<typename T>
T& get()
{
    return static_cast<T&>(get(T::type));
}

Now I can write something like this:

animal_getter ag;
ag.get<antelope>().run();

not wordier:

animal_getter ag;
static_cast<antelope&>(ag.get(animal_type::antelope)).run();

, . unit test , animal_getter (, -, unit test, , ). "get get", , . , ? :

struct IAnimalGetter
{
    virtual template<typename T> T& get() = 0;
};

, ?

, ? , ? -, , ?

+4
3

, , , - ( , ).

antelope& get_antelope();
bear& get_bear();
cat& get_cat();

, .

get_antelope().run();
get_cat().meow();

, . . switch .

- , .

 template <class A>
 A& get_animal();

 template<> antelope& get_animal<antelope>() { return get_antelope(); }
 template<> bear& get_animal<bear>() { return get_bear(); }
 template<> cat& get_animal<cat>() { return get_cat(); }
+1

, , :

struct IAnimalGetter
{
    virtual animal& get(animal_type t) = 0;

    template<typename T>
    T& get()
    {
      return static_cast<T&>(get(T::type));
    }
};

class animal_getter : public IAnimalGetter
{
public:
    animal& get(animal_type t)
    {
        // implementation
    }
};

class mock_animal_getter : public IAnimalGetter
{
public:
    animal& get(animal_type t)
    {
        // mock implementation
    }
};
0

. , . , , , . , , , . switch , , , , .

, .

If you need it, consider whether they need to control this type (i.e., the bear has a way to get a copy of the bear). Another option (as already mentioned) is to expose the static instances of each type that your recipient has.

If you do not want to manage static instances in related classes, consider having separate getters:

template<typename T>
struct IGetter
{
    virtual T Get() =0;
};

template<typename T>
struct RealGetter : public IGetter<T>
{
    static T item;
    virtual T Get()
    {
         return item;
    }
 };

template<typename T>
struct MockGetter : public IGetter<T>
{

   virtual T Get()
   {
     // some mock implementation
   }
};
0
source

Source: https://habr.com/ru/post/1682922/


All Articles