6
votes

Paramètre Lambda avec valeur de retour en option

J'essaie d'écrire une fonction comme std :: for_ach code>, que, en plus de l'utilisation normale, pouvez également prendre un std :: fonction . Une valeur de rendement fausse signifie que je veux sortir de la boucle. Le code ci-dessous est ce que j'ai obtenu jusqu'à présent.

Le deuxième appel à A.Visit ([&] (int) -> VOID) code> ne compile pas lors de l'évaluation! Visiteur (I) . Est-il possible de faire ce travail ou je suis en train d'aboyer le mauvais arbre? P>

J'utilise MSVC 2010 mais que vous voulez que le code soit généralement compatible C ++ 11. P>

#include <list>
#include <string>
#include <iostream>

struct A 
{
    std::list<int> _lst;

    template<typename _F>
    void visit(_F visitor) 
    {
        for(std::list<int>::const_iterator it = _lst.begin(), end = _lst.end() ; it != end ; it++) {
            int i = *it;
            if (std::is_void<decltype(visitor(i))>::value) {
                visitor(i);
            } else {
               if (!visitor(i)) { // <----- error C2171: '!' : illegal on operands of type 'void'
                   break;
               }
            }
        }
    }

};

int main(int argc, char* argv[])
{
    A a;
    // populate a
    for (int i = 0 ; i < 10 ; i++) { 
        a._lst.push_back(i); 
    }

    a.visit([](int i) -> bool {
        std::cout << i << std::endl;
        return i < 5;
    });

    a.visit([](int i) {
        std::cout << i << std::endl;
    });
}


5 commentaires

Le code des deux côtés de la branche If doit être correct et compilable, vous ne pouvez donc pas choisir en fonction de std :: is_void à l'intérieur du corps de la fonction.


Pourquoi utilisez-vous des noms commençant par un soulignement et une lettre majuscule telle que _f ?


C'est la convention que j'utilise pour les paramètres de modèle. Je pense que je l'ai choisi de regarder le code STL.


@KYLE_WM: Les implémentations de la bibliothèque essaient généralement très difficiles à éviter les affrontements de nom, même avec des macros méchantes (qui ne respectent pas la portée). La norme facilite sa vie en leur donnant une autorisation exclusive d'utiliser des noms en commençant par deux soulignes, une lettre de soulignement et de majuscule. Si vous n'écrivez pas à la mise en œuvre (ce qui signifie que vous souhaitez que votre code soit portable), vous ne devez pas utiliser ces identificateurs.


@Danielko Oh, c'est gênant. Merci pour les informations, je vais cesser d'utiliser.


3 Réponses :


-1
votes

Ce lambda ne renvoie pas de valeur, c'est pourquoi vous obtenez une erreur que "Visiteur" renvoie Void:

a.visit([](int i) -> bool {
    std::cout << i << std::endl;
    return true;
});


1 commentaires

Il manque le point. Les deux appels devraient fonctionner, l'objectif est de changer visiter pour le faire fonctionner.



4
votes

Votre std :: is_void doit être fait à la compilation et ne peut pas être fait à l'intérieur du corps de la fonction. Cette utilisation de la surcharge de fonction fonctionnera: xxx


4 commentaires

C'est exactement ce que j'avais mal compris. Merci!!


Notez que déclinger (visiteur (0)) ne fonctionnera pas lorsque 0 n'est pas un argument valide pour visiteur . std :: résultat_of existe à cause de cela.


Il visitent une liste de int S non une liste de types de modèles inconnus.


Comme alternative, écrivez des surcharges de do_visit qui acceptent soit un T * ou un Void * et transmettez un static_cast (nullptr) . Qui évite le besoin de std :: isame . Notez que la mise en œuvre actuelle est trop stricte quand même: elle nécessite que le type de retour de visiteur est exactement bool , non convertible vers bool .



6
votes

Voici comment je voudrais implémenter for_almost_each ; Je suis à l'aide de noms d'espace std plus de paramétrages de type à des fins de la lisibilité. xxx

i utilisé is_convertible , car il semble avoir plus de sens que isameame .


4 commentaires

Merci beaucoup, j'ai accepté la réponse de @ Troy parce que c'était d'abord, mais j'apprends beaucoup de choses à lire les vôtres aussi!


Notez également l'utilisation de résultat_of , ce qui se comporte correctement indépendamment de la manière dont l'argument doit être construit; La réponse de Troy ne fonctionne que lorsque le foncteur accepte le littéral 0 .


@KYLE_WM: Vous devez sélectionner la meilleure réponse et peut changer votre esprit précisément parce que les réponses ultérieures peuvent être meilleures. IMO C'est un exemple si celui de cette dernière réponse.


@Msalters, OK, a changé. J'avais accepté la réponse de Troy parce qu'elle corrige directement l'erreur dans mon code d'exemple (qui semble bonne, didactiquement). Mais je peux voir comment cette réponse est plus générale / plus utile aux autres recherchant la même question. Merci pour votre contribution.