Partage

Alias d'une instanciation d'une méthode template

16 avril 2018 à 22:10:08

Bonjour,

Je suis confronté à la situation suivante. J'ai une classe contenant plusieurs méthodes, ainsi qu'une méthode qui me sert de wrapper. La déclaration ressemble à cela :

class Foo{
private:
  int method1(int);
  char method2(bool, int);
  void method3();
  //...et davantages...

  template<
    typename T,
    typename ...P,
    T (Foo::*)(P...)
  > T wrapper(P...);
};

Toutes ces fonctions sont en private. Ce que je souhaiterais faire, c'est créer pour chacune de ces méthodes (le wrapper exclu) une méthode publique, qui appellerait tout simplement la méthode wrappée. Bien entendu, je pourrais tout simplement faire comme cela pour chacune des méthodes :

int Foo::wrap_method1(int arg){
  return wrapper<method1>(arg);
}

Mais cela impliquerait de faire un appel fonction supplémentaire. Ce que j'aimerais faire, c'est créer une sorte d'alias, c'est-à-dire associer à chaque méthode wrappée un nom (par exemple Foo::wrap_methodn à Foo::wrapper<methodn>). Ainsi :

Foo foo;

foo.wrap_method1(0);     //Cet appel...
foo.wrapper<method1>(0); //Et cet appel (sans prendre en compte l'encapsulation)...

/**
  ...ont le même comportement.
**/

...et ce, sans utiliser #define.

Merci de vos réponse, et bonne soirée.

Vous êtes demandeur·se d'emploi ?
Sans diplôme post-bac ?

Devenez Développeur·se web junior

Je postule
Formation
courte
Financée
à 100%
16 avril 2018 à 23:32:28

Quel est le problème avec l'appel de fonction supplémentaire ? Si c'est pour des raisons d'optimisation, le compilateur sait très bien inliner le code.

17 avril 2018 à 5:16:16

Je n'en doute pas. En réalité, un appel de fonction supplémentaire ne me dérange pas tant que ça. En revanche, je trouve ça peu pratique d'écrire ces méthodes, sachant que cela revient à produire du code supplémentaire pour un truc simple que le compilateur pourrait faire parfaitement. Je me demandais juste s'il existait une manière de faire cela en C++ pur, c'est-à-dire, sans faire appel au spécificité du compilateur.
17 avril 2018 à 10:33:55

Utilise le perfect forwarding avec les variadic templates. Mais tu es tout de même obligé de mettre tes fonctions publiques.

#include <iostream>

class foo {
public:
	void f1(int, int, int) {
		puts("f1");
	}
	void f2(bool, int, bool) {
		puts("f2");
	}

public:
	template <typename Function, typename... Args>
	void call(Function f, Args&&... args)
	{
		(this->*f)(std::forward<Args>(args)...);
	}
};

int main() {
	foo f;

	f.call(&foo::f1, 1, 2, 3);
	f.call(&foo::f2, -1, false, -2);

	return 0;
}

Ainsi, si tu as besoin de faire du code commun aux deux fonctions f1 et f2, tu peux le faire dans call. Mais bon je ne suis tout de même peu fan de la solution finale.


Si tu peux déjà utiliser C++17, tu peux même profiter de std::invoke.

-
Edité par markand 17 avril 2018 à 10:36:16

l'azerty est aux dispositions ce que subversion est aux SCM
17 avril 2018 à 22:00:38

Merci pour l'idée du std::forward. Bien que je suis parvenu à écrire mon wrapper correctement, je viens de le réécrire avec cette fonction.

Cependant, dans ce cas, il n'y a pas énormement d'avantage. Autant écrire wrapper<method1> directement, ce sera tout aussi long que f.call(method1,...)...

Alias d'une instanciation d'une méthode template

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown