Почему я не могу использовать 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&) '
2 ответа
Чтобы понять это, подумайте, что бы это значило, если бы вы просто передали литерал 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(); } )
Ну понятно второй пример не упоминает placeholders::_2
, когда accumulate
вызывает функтор с двумя аргументами, второй аргумент игнорируется, и ваш код пытается добавить int
и экземпляр внутреннего класса, который mem_fn
возвращается.
Я предлагаю вам отбросить все это bind
игры и использовать лямбду:
accumulate(cbegin(foos), cend(foos), 0,
[](int val, foo* f) { return val + f->r(); });
Намного понятнее, что здесь происходит.