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 принимает еще и кастомный функтор(=
ОтветитьУдалить