Почему я не могу использовать mem_fn Functor в bind?

Я хотел передать 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&)»

0

Решение

Ну понятно второй пример не упоминает placeholders::_2, когда accumulate вызывает функтор с двумя аргументами, второй аргумент игнорируется, и ваш код пытается добавить int и экземпляр внутреннего класса, который mem_fn возвращается.

Я предлагаю вам отбросить все это bind игры и использовать лямбду:

accumulate(cbegin(foos), cend(foos), 0,
[](int val, foo* f) { return val + f->r(); });

Намного понятнее, что здесь происходит.

2

Другие решения

Чтобы понять это, подумайте, что бы это значило, если бы вы просто передали литерал bind3й аргумент. Например, если вы сделали:

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 параметра! на самом деле имеет специальные правила для обработки 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(); } )
0

По вопросам рекламы [email protected]