Bonjour à tous.
J'adore le C++, ses subtilités et ses problèmes tordus.
En l'occurence, j'ai aujourd'hui une difficulté à base de templates.
Pour rappel, le CRTP est un mode d'héritage template assez courant, qui permet, entre autre, un polymorphisme à la compilation.
J'ai pris l'habitude d'utiliser CRTP comme nom de ce parametre template. Ca aide à repérer le pattern.
Voici donc la classe de base réelle de mon problème (à ceci près que j'ai en plus un wrapper autour du stream).
Comme vous pouvez le noter, il y a deux operator(), correspondant à deux std::function;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 template <typename Object, typename CRTP> struct streamable { void operator() (std::ostream& stream, object_type const& o) const { static_cast<CRTP&>(*this).write_into(stream, o); } void operator() (std::istream& stream, object_type const& o) const { static_cast<CRTP&>(*this).read_from(istream, o); } };
Cette classe sert de base à toute une hiérarchie de templates, pour créer un système "expression template".
Cela signifie qu'au final, je peux écrire
En gros, il s'agit d'unifier une lambda pour ostream et une pour istream.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 struct S { int a, b; }; using namespace std; int main() { auto streamer = streamer<S>("a=") + &S::a + ";b=" + &S::b+';'; S s; cin >> streamer(s); swap(s.a, s.b); cout << streamer(s); return 0; }
Mon soucis, c'est de rendre ce code compatible avec C++03. (snif)
Ca fonctionne... mais auto devient :
Du coup, ce n'est pas très pratique.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 streamer_join< streamer_join< streamer_join< streamer_join< streamer_const<S, string>, streamer_member<S, int> >, streamer_const<S, string> >, streamer_member<S, int> >, streamer_const<S, char> >
Il me faudrait un type qui soit template uniquement sur le type d'objet à manipuler, qui puisse recevoir cette classe.
J'ai bien la piste de boost::function, mais comment unir les deux interfaces?
J'ai envisagé la classe suivante
Ca fonctionnerait plutot bien, mais il y a un petit défaut: le streamable est stocké deux fois. Si vous avez une idée sur la question, je suis preneur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 template <typename Object> class Streamer { private: boost::function< void(std::ostream& stream, Object const& o) > output_interface; boost::function< void(std::istream& stream, Object const& o) > input_interface; public: template <typename CRTP> Streamer< streamable<Object, CRTP> const& interface): output_interface(interface), input_interface(interface) {} //définition des deux operator() pour appeler les interface. };
Par contre, il y a un autre défaut, plus gros.
Dans ma classe streamable réelle, les opérator() sont template sur le type de stream:
Et là, subitement, je ne peux plus stocker d'objet function, puisqu'il n'y en a pas qu'une.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 template <typename Object, typename CRTP> struct streamable { template <typename OStream> void operator() (stream_wrapper<OStream>& stream, object_type const& o) const { static_cast<CRTP&>(*this).write_into(stream, o); } };
J'en arriverai à vouloir stocker un unique_ptr d'une copie du streamable, mais n'ayant pas de type CRTP, définir le pointeur.
Je ne vois pas d'échappatoire, et j'ai vraiment besoin de définir une variable (voire un membre d'une classe).
Partager