Я не могу передать лямбда как std:: function

Давайте сосредоточимся на этом примере:

template<typename T>
class C{
    public:
    void func(std::vector<T>& vec, std::function<T( const std::string)>& f){
        //Do Something
    }
};

И теперь я пытаюсь:

std::vector<int> vec;
auto lambda = [](const std::string& s) { return std::stoi(s); };
C<int> c;
c.func(vec, lambda);

Он вызывает ошибки:

no matching function for call to ‘C<int>::func(std::vector<int, std::allocator<int> >&, main()::<lambda(const string&)>&)’
     ref.parse(vec, lambda);

Пожалуйста, объясните мне, что не подходит и как реализовать его с помощью std:: bind.

Ответы

Ответ 1

Это потому, что лямбда-функция не является std::function<...>. Тип

auto lambda = [](const std::string& s) { return std::stoi(s); };

не std::function<int(const std::string&)>, а что-то неопределенное, которое может быть присвоено std::function. Теперь, когда вы вызываете свой метод, компилятор жалуется, что типы не совпадают, поскольку преобразование означает создание временного объекта, который не может связываться с неконстантной ссылкой.

Это также не относится к лямбда-функциям, поскольку ошибка возникает, когда вы передаете нормальную функцию. Это тоже не сработает:

int f(std::string const&) {return 0;}

int main()
{
    std::vector<int> vec;
    C<int> c;
    c.func(vec, f);
}

Вы можете назначить лямбда для std::function

std::function<int(const std::string&)> lambda = [](const std::string& s) { return std::stoi(s); };

измените свою функцию-член, чтобы принять функцию по значению или const-ссылке или сделать параметр функции типом шаблона. Это будет немного более эффективным, если вы передадите указатель лямбда или нормальной функции, но мне лично нравится выразительный тип std::function в сигнатуре.

template<typename T>
class C{
    public:
    void func(std::vector<T>& vec, std::function<T( const std::string)> f){
        //Do Something
    }

    // or
    void func(std::vector<T>& vec, std::function<T( const std::string)> const& f){
        //Do Something
    }

    // or
    template<typename F> func(std::vector<T>& vec, F f){
        //Do Something
    }
};

Ответ 2

Это потому, что аргумент (std::function) является ссылкой. Это должно быть:

void func(std::vector<T>& vec, std::function<T(const std::string&)> f)
                                                                ^  ^
                                                                   |
                                                                   f not a reference

Итак, аргумент может быть преобразован в тип параметра.

Кроме того, тип функции должен совпадать. То есть он должен принять ссылку на строку.