web-dev-qa-db-fra.com

Je ne peux pas passer lambda en tant que std :: function

Concentrons-nous sur cet exemple:

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

Et maintenant, j'essaye:

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

Cela provoque des erreurs:

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

Veuillez m'expliquer ce qui ne va pas et comment l'implémenter avec std :: bind également.

41
Gilgamesz

C'est parce qu'une fonction lambda n'est pas un std::function<...>. Le type de

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

n'est pas std::function<int(const std::string&)>, mais quelque chose d'indéterminé qui peut être assigné à un std::function. Désormais, lorsque vous appelez votre méthode, le compilateur se plaint que les types ne correspondent pas, car la conversion impliquerait de créer un temporaire qui ne peut pas être lié à une référence non const.

Cela n’est pas non plus spécifique aux fonctions lambda car l’erreur se produit lorsque vous passez une fonction normale. Cela ne fonctionnera pas non plus:

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

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

Vous pouvez soit assigner le lambda à un std::function

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

, changez votre fonction membre pour prendre la fonction par valeur ou par référence constante ou transformez le paramètre fonction en type de modèle. Ce sera légèrement plus efficace au cas où vous passez un pointeur de fonction lambda ou normal, mais j'aime personnellement le type expressif std::function De la signature.

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
    }
};
30
Jens

C'est parce que l'argument (std::function) est une référence. CA devrait etre:

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

Pour que l'argument puisse être converti en type de paramètre.

En outre, le type de la fonction doit correspondre. C'est à dire. il devrait accepter une référence de chaîne.

22
bolov