2009-11-19 9 views
7

Ici, j'ai foncteur du genre de suivi:Comment réduire les arguments de modèle?

template<class T, class Foo, T Foo::*p> 
struct X { 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 

}; 

Et struct exemple:

struct FF 
{ 
    int m; 
    int r; 
}; 

Je veux utiliser le foncteur X, mais je ne veux pas spécifier explicitement l'argument de modèle comme suit :

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>()); // it work, but I don't want to write `int` and `FF` 
    std::for_each(cont.begin(), cont.end(), createx<&FF::r>());  // how I would like to use it, how to declare `createx` function? 
} 

Voici ce que j'ai essayé sans succès:

// that is what I tried, but it could not deduce T and Foo 
template<T Foo::*p, class T, class Foo> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 

// this works, but requires to write T and Foo explicitly 
template<class T, class Foo, T Foo::*p> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 
+0

Petit correctif (votre code "correct" ne compile pas): votre déclaration de type de retour de 'createx' devrait contenir' p' comme troisième paramètre de modèle, pas 'T Foo :: * p'. Ne change pas le problème, cependant. –

Répondre

8

Je viens de ne pas stocker le pointeur de membre comme argument de modèle:

template<class T, class Foo> 
struct X { 
    X(T Foo::*p): p(p) {} 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 
private: 
    T Foo::*p; 
}; 

template <class T, class Foo> 
X<T, Foo> MakeX(T Foo::*p) 
{ 
    return p; 
} 

Je ne pense pas qu'il est possible de déduire les types avec votre approche: vous ne pouvez pas utiliser un pointeur à -membre passé à une fonction qui est où la déduction de type se produit.

Editer: Cependant, il peut y avoir des solutions basées sur des macros.

Par exemple, vous pouvez faire une classe pour créer des instances de X, comme ceci:

template <class T, class Foo> 
struct XMaker 
{ 
    template <T Foo::*p> 
    X<T, Foo, p> make() { return X<T, Foo, p>(); } 
}; 

Maintenant, vous pouvez créer une marque ... fonction de déduire T et Foo:

template <class T, class Foo> 
XMaker<T, Foo> make_x_maker(T Foo::*) 
{ 
    return XMaker<T, Foo>(); 
} 

qui permet d'écrire une macro comme:

#define CREATE_X(member) make_x_maker(member).make<member>() 

Utilisation:

std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r)); 
+0

C'est un code critique dans le temps. Je ne veux pas stocker 'p'. –

+2

La question était de savoir comment écrire 'createx'. J'ai déjà une solution à la compilation et je veux juste réduire les arguments des templates. –

+0

Maintenant c'est presque nécessaire. J'accepterais cette réponse mais je n'aime pas les macros. –

1

Je ne pense pas qu'il soit possible de réduire le nombre d'arguments de modèle que vous devez spécifier si vous voulez qu'un pointeur de fonction membre arbitraire soit un argument de modèle.

Au lieu de la fonction membre pointeurs, vous pouvez utiliser un paramètre de type normal pour un foncteur qui extrait une référence:

template<typename Func> 
class X 
{ 
public: 
    explicit X(Func f = Func()) : f(f) {} 

    template<class K> 
    void operator()(K & k) const { 
     f(k) = 12 * f(k); 
    } 
private: 
    Func f; 
}; 

Ensuite, vous avez toujours la possibilité d'utiliser un foncteur spécial qui accède directement à un certain membre (si vous pensez que cela offre de meilleures performances), ou utilisez un foncteur accesseur plus général qui le fait avec un pointeur de fonction membre en tant que membre.

+2

Il est autorisé par Standard d'avoir un pointeur de fonction membre comme argument de modèle. –

+1

Oui, je sais. Le "Je ne pense pas que ce soit possible" fait référence au titre de la question. Je n'ai pas dit "les pointeurs de fonction membres ne sont pas autorisés comme paramètres de gabarit". S'il vous plaît lire les réponses plus attentivement avant de downvote. Je vais essayer de faire de mon mieux la prochaine fois pour écrire des réponses qui ne peuvent pas être mal comprises. Merci. – sellibitze

+0

Cette réponse n'a rien à voir avec ma question. –

1

Je voudrais poser une question: avez-vous vraiment besoin de spécifier tous ces arguments?

struct XR 
{ 
    template <class Foo> 
    void operator()(Foo& foo) const { foo.r = 12 * foo.r; } 
}; 

Cela fonctionne, il n'y a pas besoin d'une méthode make supplémentaire, il fonctionne:

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), XR()); 
} 

Je préfère ne pas être trop générique lorsque je crée des modèles.

Si vous avez besoin d'un operator() plus complexe, vous pouvez toujours faire de lourdes charges à l'intérieur.

En outre, vous pouvez considérer Boost.Bind, si vous souhaitez vraiment extraire des fonctions de pointeur et des références aux attributs.

EDIT:

J'ai une idée, ce sera un peu différent et ne comporte aucune macro magie, ni même magie métaprogrammation. Pourquoi ne pas simplement utiliser un typedef et en finir avec lui? D'accord, peut-être pas aussi automatisé que vous le souhaitez ... mais vous n'avez qu'à taper une fois, après tout.

typedef X<int,FF,&FF::m> X_FF_m; // once 

std::for_each(cont.begin(), cont.end(), X_FF_m()); 

semble moins taper que

std::for_each(cont.begin(), cont.end(), createX<&FF::m>()); 

répété à plusieurs reprises. J'utilise à peine des modèles nus dans mon code, je préfère les typer pour améliorer la lisibilité.

+0

Ce n'est pas une option. 'struct XR' utilise' .r'-member. Si je veux utiliser le membre '.m', dois-je définir un nouveau' struct XM'? Et qu'en est-il d'autres membres? –

+0

Une structure par membre, rien d'extraordinaire, juste quelque chose qui fonctionne et qui est simple. Bien sur dans votre exemple vous avez présenté une structure avec 2 attributs et je pense qu'elle s'adapte très bien à 4 ou 5 ... –

Questions connexes