2013-03-12 1 views
1

Вот упрощенная версия моего кода:Как элегантно избежать дублирования кода при <изменениях>?

template<typename TIterator> 
TIterator findMaximalPosition(TIterator begin, TIterator end) 
{ 
    TIterator result(begin); 
    for (TIterator it = begin + 1; it != end; ++it) 
    { 
     if ((*it)->value > (*result)->value) // Here I just need to change to "<" 
      result = it;      // to get a findMinimalPosition 
    } 
    return result; 
} 

template<typename TIterator> 
TIterator findMinimalPosition(TIterator begin, TIterator end) 
{ 
    // almost the same 
} 

Это просто упрощенный пример. Мой код полон мест, где две функции одинаковы, за исключением знака < или >, или следует использовать ++ или --.

Мой вопрос:

Есть ли способ, как уменьшить это дублирование в коде без

  1. Уничтожение читаемость
  2. Уменьшение производительности?

Я думал об использовании указателя на оператора (либо <, либо >) в качестве параметра шаблона. Это не должно уменьшать производительность, поскольку указатель будет постоянной времени компиляции. Есть ли какой-то лучший или обычно используемый способ?

EDIT:

Так что я сделал на основе ответов было реализовать:

template <typename TIterator, typename TComparison> 
TIterator findExtremalPosition(TIterator begin, TIterator end, 
           TComparison comparison); 

, а затем просто позвонить:

return findExtremalPosition(begin, end, std::less<double>()); 

и

return findExtremalPosition(begin, end, std::greater<double>()); 

I надеюсь, это то, что вы eant. Я полагаю, что после некоторого борющегося аналогичного решения можно сделать для ++ и -- операторов.

+6

См. ['Max_element'] (http://en.cppreference.com/w/cpp/algorithm/max_element). –

+0

Спасибо, проблема в том, что я часто получаю эту ситуацию, и бывают случаи, когда стандартный алгоритм не будет выполнять эту работу. И что вы подразумеваете под «==»? –

+2

@MartinDrozdik: ... еще, см. 'Max_element'. Даже если вы не можете использовать его, у него есть решение проблемы. –

ответ

5

Я хотел бы сделать общую функцию, которая принимает предикат и использовать std::greater и std::less в качестве аргумента этой функции для данного типа для реализации findMaximalPosition и findMinimalPosition соответственно.

+2

Правильное решение. Функторы обычно более эффективны, чем указатели на функции, потому что они встроены. – MSalters

+0

Обратите внимание, что вы все равно будете дублировать объектный код. –

+2

@MSalters Для простых вещей, подобных этому, компилятор должен иметь возможность встроить версии с указателем на функцию. –

1

Как было предложено Ivaylo Strandjev, одним из возможных решений является использование предикатов.

Так что, если вы измените функцию для работы с предикатами ...

typename std::vector<int> vec; 

template<typename TIterator, bool (*Predicate)(const TIterator &, const TIterator &)> 
TIterator findPosition(TIterator begin, TIterator end) 
{ 
    TIterator result(begin); 
    for (TIterator it = begin + 1; it != end; ++it) 
    { 
     if (Predicate(it, result)) 
      result = it; 
    } 
    return result; 
} 

... и потом, вы определить некоторые предикаты, которые помогают Вам достичь своей цели ...

bool lesser(const vec::iterator &a, const vec::iterator &b) 
{ 
    return (*a) < (*b); 
} 

bool greater(const vec::iterator &a, const vec::iterator &b) 
{ 
    return (*a) > (*b); 
} 

... тогда вы могли бы сделать это:

vec::iterator min = findPosition<typename vec::iterator, lesser>(v.begin(), v.end()); 
vec::iterator max = findPosition<typename vec::iterator, greater>(v.begin(), v.end()); 

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

bool weird(const vec::iterator &a, const vec::iterator &b) 
{ 
    return ((*a) | (*b)) & 0x4; 
} 

vec::iterator weird = findPosition<typename vec::iterator, weird>(v.begin(), v.end()); 

Пример here.

Но прежде чем делать это, проверьте, выполнил ли это задание Algorithms library.

Думаю, что это выглядит довольно аккуратно и просто.

Надеюсь, это поможет.

+0

Обычно предикат не принимается как аргумент шаблона, а всего лишь один параметр. – GManNickG

+0

@GManNickG хороший пункт! теперь, когда вы упомянули об этом, я не знаю, почему я использовал его в качестве шаблона параметра: O –

Смежные вопросы