Оптимизация цикла и предотвращение дублирования кода в специализации шаблона

0

Предположим, что мы имеем функцию

template< typename A, typename B, typename C >
void function(vector<A>& keyContainer, int a, int b, int c, boost::function<bool(B&)> selector, C* objPointer = NULL)
{
    BOOST_FOREACH(const A& key, keyContainer)
    {
        B* pVal = someGetObjFunction(objPointer, key);
        if(pVal)
        {
            if(selector && selector(*pVal))
            {
                pVal->someOtherFunction(1,2,3);
            }
            //some more code
        }
    }
}

Это выглядит плохо, потому что он всегда войдет в

if(selector && selector(*pVal))

даже если это NULL, очевидный подход к исправлению этого будет:

template< typename A, typename B, typename C >
void function(vector<A>& keyContainer, int a, int b, int c, boost::function<bool(B&)> selector, C* objPointer = NULL)
{
    if(selector)
    {
        BOOST_FOREACH(const A& key, keyContainer)
        {
            B* pVal = someGetObjFunction(objPointer, key);
            if(pVal)
            {
                if(selector(*pVal))
                {
                    pVal->someOtherFunction(1,2,3);
                }
                //some more code
            }
        }
    }
    else
    {
        BOOST_FOREACH(const A& key, keyContainer)
        {
            B* pVal = someGetObjFunction(objPointer, key);
            if(pVal)
            {
                pVal->someOtherFunction(1,2,3);
                //some more code
            }
        }
    }
}

Но это привело к большому дублированию кода, другой подход будет делать специализацию для случая, когда функция NULL, но не будет ли она почти такой же, как в примере выше? Есть ли другой способ сделать это без дублирования всего кода?

  • 0
    Вы измерили оригинальное решение и обнаружили, что проверка selector для NULL является узким местом, и что ваше альтернативное решение приводит к заметному улучшению? Если вы заботитесь о производительности, вы бы измерили ее. Если вы не измерили, это показывает, что вам все равно. «Преждевременная оптимизация - корень всего зла». ~~ Дональд Кнут.
  • 0
    Некоторые компиляторы могут хорошо выполнять условия внутри циклов. Если он докажет, что bool значение selector не меняется.
Показать ещё 2 комментария
Теги:
optimization
templates
loops
specialization

1 ответ

1
Лучший ответ

Ваше описание проблемы немного запутанно. Вы не проверяете NULL, потому что selector не является указателем. Вместо этого вы проверяете, empty() объект boost::function empty(): http://www.boost.org/doc/libs/1_55_0/doc/html/boost/function.html#idp54857000-bb.

Кроме того, ваши два блока кода не эквивалентны. Кажется, вы указываете, что хотите выполнить внутренний цикл, если либо (селектор предоставлен, либо истина), либо (селектор не указан).

Итак, ваш первый блок кода должен быть:

template< typename A, typename B, typename C >
void function(vector<A>& keyContainer, int a, int b, int c, boost::function<bool(B&)> selector, C* objPointer = NULL)
{
    BOOST_FOREACH(const A& key, keyContainer)
    {
        B* pVal = someGetObjFunction(objPointer, key);
        if(pVal)
        {
            if(!selector || (selector && selector(*pVal)))
            {
                pVal->someOtherFunction(1,2,3);
            }
            //some more code
        }
    }
}

Это логически эквивалентно вашему второму блоку кода.

Как отметил Игорь Тендетник, вам нужно действительно измерить код, чтобы увидеть, где находится узкое место. Вероятно, это не проверка на то, что селектор пуст.

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

template< typename A, typename B, typename C >
void function(vector<A>& keyContainer, int a, int b, int c, boost::function<bool(B&)> selector, C* objPointer = NULL)
{
    bool check_selector = !selector.empty();
    BOOST_FOREACH(const A& key, keyContainer)
    {
        B* pVal = someGetObjFunction(objPointer, key);
        if(pVal)
        {
            if(!check_selector || (check_selector && selector(*pVal)))
            {
                pVal->someOtherFunction(1,2,3);
            }
            //some more code
        }
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню