Я хотел передать mem_fn
аргумент bind
но компилятор, похоже, не позволяет этого.
Например, это работает нормально:
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)));
Но когда я пытаюсь использовать mem_fn
Функтор получаю о странице ошибок:
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)));
/usr/include/c++/6/bits/stl_numeric.h: создание экземпляра ‘_Tp std :: аккумулировать (_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx :: __ normal_iterator>; _Tp = int; _BinaryOperation = std :: _ Bind (std :: _ Placeholder<1>, std :: _ Mem_fn)>] ’:
prog.cpp: 20: 102: требуется отсюда
/usr/include/c++/6/bits/stl_numeric.h:154:22: ошибка: нет совпадения для вызова ‘(std :: _ Bind (std :: _ Placeholder<1>, std :: _ Mem_fn)>) (int&, foo * const&)»
Ну понятно второй пример не упоминает placeholders::_2
, когда accumulate
вызывает функтор с двумя аргументами, второй аргумент игнорируется, и ваш код пытается добавить int
и экземпляр внутреннего класса, который mem_fn
возвращается.
Я предлагаю вам отбросить все это bind
игры и использовать лямбду:
accumulate(cbegin(foos), cend(foos), 0,
[](int val, foo* f) { return val + f->r(); });
Намного понятнее, что здесь происходит.
Чтобы понять это, подумайте, что бы это значило, если бы вы просто передали литерал bind
3й аргумент. Например, если вы сделали:
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, 13))
Результат был бы size(foos) * 13
, так как plus
использовал бы 13
как это добавить на каждой итерации.
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)))
Не скомпилируется, потому что пытается передать результат mem_fn(&foo::r)
как дополнение к plus
, Поскольку это не может быть преобразовано в int
plus
не могу принять это. Но даже если бы он мог быть преобразован в int
, это не то, что вы ищете, вы хотите взять 2й аргумент и вызов foo::r
на нем, передавая результат plus
, Таким образом, мы знаем, что нам нужно увидеть, placeholders::_2
используется где-то в заявлении, передающем 2й аргумент для вызова его r
метод.
Нам нужно связать placeholders::_2
быть привязанным к функтору, который назовет r
метод по своему параметру. Связывание, конечно, потребует bind
, но на самом деле bind
может взять метод, как это 1улица аргумент.
Тем не менее, bind(&foo::r, placeholders::_2)
утверждение из вашего рабочего кода не имеет смысла в не вложенной форме; этот функтор даже не принимает 2 параметра! C ++ на самом деле имеет специальные правила для обработки bind
вложенный в другой bind
, чтобы они могли поделиться внешним bind
это заполнители, чтобы не было способа передать связанный аргумент вложенному выражению:
Если сохраненный аргумент arg имеет тип
T
для которогоstd::is_bind_expression<T>::value == true
(например, другойbind
выражение было передано непосредственно в первоначальный вызовbind
), затемbind
выполняет композицию функций: вместо передачи объекта функции, который должен возвращать подвыражение bind, подвыражение вызывается с нетерпением, а его возвращаемое значение передается внешнему вызываемому объекту. Еслиbind
подвыражение имеет любые аргументы-заполнители, они разделяются с внешнимbind
,
Единственный способ использовать mem_fn
в этом выражении было бы передать его результат bind
для передачи placeholders::_2
: bind(mem_fn(&foo::r), placeholders::_2)
Это работает, но это ненужный шаг, когда простой bind(&foo::r, placeholders::_2)
будет достаточно. Таким образом, лучший способ сгенерировать этот функтор — воспользоваться предложенным предложением:
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)))
Или с помощью лямбды:
accumulate(cbegin(foos), cend(foos), 0, [](const int augend, const auto& addend) { return augend + addend.r(); } )