C++ - Статический полиморфизм против полиморфизма времени выполнения против лямбды

Я узнал разницу между статическим и динамическим полиморфизмом, и с тех пор я много чего на нем читал. Плюс, поскольку я обнаружил, что реализую статический полиморфный интерфейс (таким образом, что класс может использовать объект с определением базового класса, не зная, с каким "производным" классом был создан объект).

Поэтому я провел небольшой тест, чтобы сравнить эти разные реализации.

Вот код:

#include <functional>
#include <iostream>
#include <ctime>
#include <chrono>
#include <memory>

class BaseLambda
{
    public:
        double run(double param){return m_func(param);};
    protected:
        BaseLambda(std::function<double(double)> func) : m_func(func) {  };
        std::function<double(double)> m_func;
};

class DerivedLambda : public BaseLambda
{
    public:
        DerivedLambda() : BaseLambda([](double param){return DerivedLambda::runImpl(param);}) {  };
    private:
        static double runImpl(double param) {return (param * param) / 2.5;};
};

class BaseVirtual
{
    public:
        double run(double param){return runImpl(param);};
    protected:
        virtual double runImpl(double param) = 0;
};

class DerivedVirtual : public BaseVirtual
{
    protected:
        double runImpl(double param) {return (param * param) / 2.5;};
};


template<class C> class BaseTemplate
{
    public:
        double run(double param){return static_cast<C*>(this)->runImpl(param);};
};

class DerivedTemplate : public BaseTemplate<DerivedTemplate>
{
    public:
        double runImpl(double param) {return (param * param) / 2.5;};
};


int main()
{
    std::clock_t  c_start = std::clock();

    std::unique_ptr<BaseVirtual> baseVirtual = std::make_unique<DerivedVirtual>();
    for(unsigned int i = 0 ; i < 1000000 ; ++i) {
        auto var = baseVirtual->run(10.6);
    }
    baseVirtual.reset(nullptr);

    std::clock_t  c_end = std::clock();

    std::cout << "Execution time with virtual : "
        << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms" << std::endl;


    c_start = std::clock();

    std::unique_ptr<BaseLambda> baseLambda = std::make_unique<DerivedLambda>();
    for(unsigned int i = 0 ; i < 1000000 ; ++i) {
        auto var = baseLambda->run(10.6);
    }
    baseLambda.reset(nullptr);

    c_end = std::clock();

    std::cout << "Execution time with lambda : "
        << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms" << std::endl;


    std::unique_ptr<BaseTemplate<DerivedTemplate>> baseTemplate = std::make_unique<DerivedTemplate>();
    for(unsigned int i = 0 ; i < 1000000 ; ++i) {
        auto var = baseTemplate->run(10.6);
    }
    baseTemplate.reset(nullptr);

    c_end = std::clock();

    std::cout << "Execution time with template : "
        << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms" << std::endl;
}

Дело в том, что когда я запускал это, виртуальная реализация была самой быстрой, в то время как статический полиморфизм должен был быть быстрее. Вот пример результата выполнения:

Время выполнения с виртуальным: 53 мс
Время исполнения с лямбдой: 94 мс
Время исполнения по шаблону: 162 мс

Я предполагаю, что это из-за некоторой оптимизации компилятора. Я компилирую с GCC 6.3.0.

Мой вопрос: почему реализация шаблона самая медленная? Это действительно из-за оптимизации компилятора, и если да, то каковы они и как я могу изменить свой тест, чтобы иметь "реальное" время выполнения? И если нет, что я сделал не так?

0 ответов

Другие вопросы по тегам