7
votes

Toute fonction d'argument de modèle

#include <iostream>

void padd(int a, int b) { std::cout << a + b << std::endl; }
void psub(int a, int b) { std::cout << a - b << std::endl; }

template <??? op>
class Foo {
public:
    template<typename... Arguments>
    void execute(Arguments... args) {
        op(args ...);
    }
};

int main() {
    auto f1 = Foo<padd>();
    f1.execute(5, 6); // ideally would print 11

    auto f2 = Foo<psub>();
    f2.execute(5, 6); // ideally would print -1

    return 0;
}
I am trying to figure out how to bind functions (and, if possible, template functions) as template parameters in C++.As it stands I am not aware if this is possible.A kicker here is that the function signatures are not guaranteed to be similar.edit: thanks to @sehe and @Potatoswatter, my current solution is thus: http://ideone.com/0jcbUi. Will write up answer when appropriate.

3 commentaires

Just modèle ?


@bill


Voici un exemple de travail d'utilisation des fonctions et des pointes-fonctionnalités membres comme des arguments de modèle, avec une option bonus C ++ 98-compatible: Stackoverflow.com/questions/17218712 / ...


3 Réponses :


6
votes

Je suggérerais de laisser le compilateur à s'inquiéter de la résolution des signatures de fonction le cas échéant. http://ideone.com/zelt1e (code inclus ci-dessous).

Si vous devez adapter les ensembles de surcharge ou des interfaces polymorphes, je suggérerais également de regarder boost_phoenix_adapt_function.

Modifier En réponse aux commentaires: Voici une démonstration de la manière dont vous pourriez utiliser strictement des pointeurs et / ou un pointeur. fonctions de membre directement en tant qu'arguments de fonction. C'est l'autre approche extrême: http://ideone.com/120EZS

Code complet xxx


4 commentaires

Ce serait ce que je viserais (bien qu'avec un attribut privé ) ... mais je me demande si on peut lier une fonction comme paramètre de modèle. Il ne semble pas différent d'un Char Cons * dans ce que l'instance est une constante de compilation, mais je ne peux pas sembler trouver la syntaxe droite si elle est bien possible.


@Matthieuum. Oui, vous pouvez lier les fonctions en tant que paramètres de modèle. Seulement, vous êtes sujet à obtenir une explosion d'instanciation de modèle dans ce cas. Il peut également fonctionner pour les fonctions des membres


@Matthieuum. J'ai ajouté un ancien échantillon de code qui utilise précisément l'approche que vous semblez obtenir à


Merci, c'est exactement ce que je devais vraiment; La syntaxe est étrange, mais cohérente avec d'autres usages de pointes de la fonction.



3
votes

Il suffit de faire l'observation que vous n'avez pas d'état d'exécution ou de votre état d'exécution. En partie une inférence de vos commentaires dans la salle de discussion C ++.

Les fonctions n'ont pas de types uniques. Si vous voulez aller générer un type unique qui capture quelle fonction em> doit être appelé, utilisez un modèle de classe pour le faire. P> xxx pré>

C'est essentiellement le identique à std :: integral_constant code> mais supprime intégrale code> du nom pour enregistrer la confusion. (En fait, j'ai seulement testé cela en utilisant std :: integral_constant code>, si vous voulez être plus propre, il est à vous de choisir.) P>

Vous pouvez désormais donner aux fonctions types distincts qui sont apatrides, Foncteurs constructibles par défaut. P>

typedef constant< decltype( & padd ), padd > padd_type;
typedef constant< decltype( & psub ), psub > psub_type;

padd_type()( 2, 3 ); // prints 5


5 commentaires

+1 belle écriture-up. Notez que mon édition déjà liée à une implémentation plus complète de cela, permettant également des fonctions de pointeur à membre.


@sehe sauf, comme dans le code de la question, cela met tout dans l'argument du modèle. Sauf si encapsulé dans un identifiant de template, un pointeur de fonction serait autrement exécuté de l'état d'exécution.


@Potaswatter hmm? Soit vous avez manqué, ou le Démo lié vous confondu sur l'application. Je vous suggère de vous concentrer sur le détail Espace de noms et remarquez le modèle Rappel statique en ligne Bind (t * o) avec la structure locale. Le reste est juste une plomberie pour faire l'extraction de la signature et l'accrocher à un scénario d'utilisation quelqu'un d'autre une fois.


@sehe Le type de retour de cette fonction ne peut pas contenir le PTMF, et il est passé à travers le constructeur du membre Tfunc Callback <...> :: Func . Donc, bien que cela prend un argument de modèle de compilation, il est utilisé uniquement aussi loin que je peux voir pour initialiser un objet d'exécution.


Hmm. Je n'ai pas le temps de réaliser l'échantillon. Cela pourrait être différent de ce que je me souviens. Dammit. Ça va devoir attendre ... :(



0
votes

Grâce à l'aide de Poatoswatter et de SEHE dans le salon C ++ et ici, j'ai formulé la solution à ma question.

#include <iostream>
#include <functional>

template <typename func_t, func_t func>
struct Foo {
    template <typename... Arguments>
        void execute(Arguments... args) {
                func(args ...);
        }
};

template <typename T, typename func_t, func_t func>
struct FooMember {
        T member;

        FooMember(T member) : member(member) {}

        template <typename... Arguments>
        void execute(Arguments... args) {
                std::function<void(T&, Arguments ...)> f(func);
                f(this->member, args ...);
        }
};

struct Bar {
        int z;

        Bar(int z) : z(z) {}
        void add(int x, int y) { std::cout << x + y + z << std::endl; }
};

void padd(int x, int y, int z) { std::cout << x + y + z << std::endl; }

int main() {
        auto a = Foo<decltype(&padd), &padd>();
        auto b = FooMember<Bar, decltype(&Bar::add), &Bar::add>(Bar(2));

        a.execute(4, 5, 6); // prints 4+5+6 : 15
        b.execute(4, 5); // prints 4+5+a.z : 4+5+2 : 11

        return 0;
}


0 commentaires