namespace
{
template<class T>
class Multiply
{
public:
Multiply(T& result) : TotalResult(result)
{
}
void operator()(const T& v)
{
TotalResult *= v;
}
private:
T& TotalResult;
};
}
void main(void)
{
int result = 1;
Multiply<int> functor(result);
int buffer[] = {1, 2, 3, 4};
std::for_each(buffer, buffer + 4, functor);
std::cout << "Result = " << result;
}
Поскольку for_each принимает последний параметр по значению, то функтору нужно передавать ссылку извне. Также, чтобы где-то сохранять ссылку на результат нам пришлось написать класс. Однако можно решить задачу и по-другому, используя std::bind1st.
Размышления приводят к следующему коду, который не компилируется:
namespace
{
template<class T1, class T2>
void Multiply(T1& result, const T2& value)
{
result *= value;
}
}
void main(void)
{
int result = 1;
int buffer[] = {1, 2, 3, 4};
std::for_each(buffer, buffer + 4,
std::bind1st(std::ptr_fun(Multiply<int, int>),
result));
std::cout << "Result = " << result;
}
MSVS 2010 выдает ошибку где-то во внутренностях STL:"error C2535: 'void std::binder1st<_Fn2>::operator ()(const int &) const' : member function already defined or declared". Кусок кода, который не может скомпилироваться:
result_type operator()(const argument_type& _Right) const
{// apply functor to operands
return (op(value, _Right));
}
result_type operator()(argument_type& _Right) const
{// apply functor to operands
return (op(value, _Right));
}
Медитация над кодом и длинной "портянкой" от компилятора проясняет следующие моменты: все дело во втором параметре const int&. Казалось бы достаточно убрать const, но это не решит проблемы. Покопавшись на flipcode, я обнаружил что проблема обсуждалась уже давно - ошибка при проектировании bind1st, bind2nd + новый стандарт С++. Варианты решения:
- Использовать передачу по значению
- Использовать указатели
- Забить и использовать bind
std::for_each (buffer, buffer + 4, std::bind(Multiply<int, int>, std::ref(result),
std::placeholders::_1));
Обратите внимание на std::ref. Без этого параметр будет приниматься по значению.Вот примерно так можно медитировать над, казалось бы, простой задачей. Хотя всего этого можно было бы избежать, если просто придерживаться правила
Я в плюсах не шарю, но в функциональных языках есть полезная функция reduce или foldl, которая делает как раз то, что надо. Погуглил, нашёл accumulate.
ОтветитьУдалитьhttp://ideone.com/fnaTN
А ты на чем пишешь? Спасиб за ссылку, да не знал что accumulate принимает еще и кастомный функтор(=
ОтветитьУдалить