34 votes

Déduction automatique du type d'argument et fonctions lambda anonymes

Disons que j'ai ces lignes de code ;

std::vector<int> ints;
std::for_each(ints.begin(), ints.end(), [](int& val){ val = 7; });

Cependant, je ne veux pas spécifier le type d'argument dans mes fonctions lambda, c'est-à-dire que je veux écrire quelque chose comme ceci ;

std::for_each(ints.begin(), ints.end(), [](auto& val){ val = 7; });

Y a-t-il un moyen d'y parvenir ?

(boost::lambda n'a pas besoin que les types soient spécifiés...)


Mise à jour :

Pour l'instant, j'utilise une macro : #define _A(container) decltype(*std::begin(container)) pour que je puisse le faire :

std::for_each(ints.begin(), ints.end(), [](_A(ints)& val){ val = 7; });

1 votes

Au moins pour cela, pourquoi ne pas simplement std::fill(ints.begin(), ints.end(), 7); ?

8 votes

Oui, dans ce cas std::fill pourrait être utilisé, cependant, ce n'est pas ma question.

0 votes

C'est pourquoi je l'ai inscrit comme un commentaire, et non comme une réponse...

30voto

Anthony Williams Points 28904

Non. "Lambdas polymorphes" est le nom donné à cette fonctionnalité lors des discussions du comité C++, et elle n'a pas été normalisée. Les types de paramètres d'un lambda doivent être spécifiés.

Vous pouvez utiliser decltype cependant :

std::for_each(ints.begin(), ints.end(), [](decltype(*ints.begin())& val){ val = 7; });

2 votes

Bon sang, j'ai développé un bon flux en utilisant l'auto aussi souvent que possible.

2 votes

Typedef decltype(*beg(ints)) type ; si vous pensez que la syntaxe decltype est laborieuse.

3 votes

Les lambdas polymorphes/génériques font cependant partie du C++14 : fr.wikipedia.org/wiki/C%2B%2B14#Générique_lambdas

15voto

David Stone Points 3822

La syntaxe que vous préférez est légale à partir de C++14, et est appelée lambda générique ou lambda polymorphe.

http://isocpp.org/blog/2013/04/n3649-generic-polymorphic-lambda-expressions-r3

auto lambda = [](auto x) { return x; };
lambda(5);
lambda("hello");
lambda(std::vector<int>({5, 4, 3}));

À partir de C++20, nous pouvons également utiliser cette syntaxe pour les fonctions régulières :

auto f(auto x) { return x; }

3voto

O.C. Points 4328

Si vous avez un conteneur, vous pouvez essayer quelque chose comme ceci

template<typename Container>
void reset(Container c)
{
   for_each(c.begin(),c.end(),[](typename Container::reference val) { val=7; });
}

0 votes

Si votre fonction n'est pas une fonction template mais travaille sur un type concret (comme c'est mon cas), vous pouvez simplement faire : std::for_each(ints.begin(), ints.end(), [](ints::reference val) { ... });

0voto

Michael Price Points 9

Essayez ça :

#include <functional>
#include <algorithm>
#include <iostream>

template <typename ValTy>
std::function<void(ValTy&)> polymorphicLambda ()
{
    return std::function<void(ValTy&)> ([](ValTy& val) -> void { val = 7; } );
}

int main()
{
    std::vector<int> ints(5);

    std::generate_n(ints.begin(), 5, []() { return 0; });
    std::for_each(ints.begin(), ints.end(), [](int& val) { std::cout << val << "\t"; });
    std::cout << std::endl;

    std::for_each(ints.begin(), ints.end(), polymorphicLambda<int>());
    std::for_each(ints.begin(), ints.end(), [](int& val) { std::cout << val << "\t"; });
    std::cout << std::endl;

    std::vector<double> doubles(5);

    std::generate_n(doubles.begin(), 5, []() { return 0; });
    std::for_each(doubles.begin(), doubles.end(), [](double& val) { std::cout << val << "\t"; });
    std::cout << std::endl;

    std::for_each(doubles.begin(), doubles.end(), polymorphicLambda<double>());
    std::for_each(doubles.begin(), doubles.end(), [](double& val) { std::cout.precision(2); std::cout << std::fixed << val << "\t"; });
    std::cout << std::endl;

    return 0;
}

Vous pourriez également être en mesure de faire des choses amusantes avec des lambdas qui ne retournent pas void et aussi avec des modèles variadiques pour passer plusieurs paramètres à la lambda.

3 votes

Je ne comprends pas c'est quoi la victoire ?

0 votes

Le gain est de ne pas avoir à redéclarer votre lambda pour chaque type d'argument. Mais cela ne répond pas à votre question

1 votes

Je ne comprends pas non plus pourquoi vous utilisez cette fonction au lieu d'une déclaration de fonction de modèle standard.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X