#include <iostream>
#include <memory>

class Base
{
    public:
        Base() = default;
        virtual ~Base() = default;
        virtual void run() = 0;
};

class Derived1: public Base
{
    public:
        Derived1() = default;
        ~Derived1() override = default;
        void run() override
        {
        	std::cout << "  Derived1";
        }
};

class Derived2: public Base
{
    public:
        Derived2() = default;
        ~Derived2() override = default;
        void run() override
        {
        	std::cout << "  Derived2";
        }
};

// This function works but increase count
void doGenericCopy(std::shared_ptr<Base> ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// This function works without increase count = OK !
void doSpecificD1(std::shared_ptr<Derived1>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// Compilation error = FAILED !
void doGeneric(std::shared_ptr<Base>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// Working fine for all Derivate = OK !
template<typename CLASS>
void doGenericTemplate(std::shared_ptr<CLASS>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

void doClassic(Base& ptr)
{
    ptr.run();
    std::cout << std::endl;
}

int main()
{
    auto d1 = std::make_shared<Derived1>();
    auto d2 = std::make_shared<Derived2>();
    
    std::cout << "With copy: " << std::endl;
    doGenericCopy(d1);
    doGenericCopy(d2);
    
    std::cout << "Specific: " << std::endl;
    doSpecificD1(d1);
    
    std::cout << "Template: " << std::endl;
    doGenericTemplate(d1);
    doGenericTemplate(d2);
    
    // Compilation issue
    //doGeneric(d1);
    
    {
         std::cout << "Classic: " << std::endl;
         Derived1 c1;
         Derived2 c2;
         doClassic(c1);
         doClassic(c2);
    }
}
