ptr_fun с лямбда-функцией - PullRequest
       2

ptr_fun с лямбда-функцией

5 голосов
/ 12 декабря 2011

У меня есть следующая программа, которая использует ptr_fun с лямбда-функцией.

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;
int main()
{
    string target="aa";
    vector<string> v1;
    v1.push_back("aa");
    v1.push_back("bb");
    auto stringcasecmp=[](string lhs, string rhs)->int
    {
        return strcasecmp(lhs.c_str(), rhs.c_str());
    };

    auto pos = find_if(
        v1.begin(), v1.end(),
        not1( bind2nd(ptr_fun(stringcasecmp), target) )
        );

    if ( pos != v1.end())
    cout <<   "The search for `" << target << "' was successful.\n"
        "The next string is: `" << pos[1] << "'.\n";
}

Я получаю следующие сообщения об ошибках.

stackoverflow.cpp: In function ‘int main()’:
stackoverflow.cpp:21:41: error: no matching function for call to ‘ptr_fun(main()::<lambda(std::string, std::string)>&)’
stackoverflow.cpp:22:6: error: unable to deduce ‘auto’ from ‘<expression error>’

Как изменить код (минимально)сделать компиляцию?

Ответы [ 2 ]

9 голосов
/ 12 декабря 2011

bind2nd (§D.9) и ptr_fun (§D.8.2.1) устарели в C ++ 11.Вы можете просто написать другую лямбда-функцию в find_if:

auto pos = find_if(v1.begin(), v1.end(),
                   [&](const std::string& s) {
                        return !stringcasecmp(s, target); 
                   });

ptr_fun(<lambda>) не будет работать, потому что ptr_fun предназначен для C ++ 03 для преобразования указателя на функциюобъект для других адаптеров.Лямбда уже является функциональным объектом, поэтому ptr_fun не требуется.

bind2nd ожидает, что функциональный объект определит элементы second_argument_type и result_type, что неверно для лямбды, поэтому написание bind2nd(<lambda>, target) также не будет работать.Но в C ++ 11 есть универсальная замена, которая работает:

std::bind(stringcasecmp, std::placeholders::_1, target)

Однако bind не возвращает объект функции в стиле C ++ 03, чего ожидает not1: для этого требуетсятип результата bind для определения argument_type члена, который не существует.Поэтому окончательное выражение

std::not1(std::bind(stringcasecmp, std::placeholders::_1, target))

будет не работать.Самый простой обходной путь - просто используйте другую лямбду, которую я написал выше.

В качестве альтернативы, вы можете определить общий отрицатель:

template <typename Predicate>
struct generic_negate
{
    explicit generic_negate(Predicate pred) : _pred(pred) {}

    template <typename... Args>
    bool operator()(Args&&... args)
    {
        return !_pred(std::forward<Args>(args)...);
    }
private:
    Predicate _pred;
};

template <class Predicate>
generic_negate<Predicate> not_(Predicate pred)
{
    return generic_negate<Predicate>(pred);
}

....

auto pos = find_if(v1.begin(), v1.end(), not_(bind(stringcasecmp, _1, target)));

Пример: http://ideone.com/6dktf

0 голосов
/ 12 декабря 2011

Попробуйте pointer_to_binary_function<string,string,int>(stringcasecmp) вместо ptr_fun(stringcasecmp)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...