Lut.
Dans c++03, la déclaration d'une class friend ne peut pas être un type dépendant. En gros, on ne peut pas faire ceci:
Maintenant si T est lui même paramétré par rapport à A, ça ne va pas arranger les choses.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 template<typename T> struct A { // illegal. "T" est un template argument friend class T; };
Pour comprendre ce que je souhaite faire, voici un code réduit au minimum, qui fonctionne et qui fait intervenir les bonnes vieilles notions de Car et Engine
Ce que je souhaiterais faire pour la class engine est ceci:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include<iostream> template<typename Engine> struct car { void start() { Engine e; e.priv = 1; std::cout << e.priv; } }; struct engine { // members... private: // seul un "car" est sensé instancier un engine engine() : priv(0) { } int priv; // OK. mais prob: le type "car" est trop spécifique template<typename Engine> friend class car; }; int main() { car<engine> c; c.start(); return 0; }
On comprend tout de suite que les types car et engine sont mutuellement corrélés et on tombe sur un problème de déclaration récursive (en plus du problème de déclaration du friend).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 // pas bon. ridicule. // pas bon non plus avec template<template<typename T> class Car> template<typename Car> struct engine { // members... private: engine() : priv(0) { } int priv; // illegal. "Car" est un template argument template<typename Engine> friend class Car; };
Pour contourner le problème, j'ai fait ceci:
- la classe car dérive d'une class template car_base qui sera friend de engine:
- le type paramétré car_base est déclaré friend de engine:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 template<typename Engine> struct car_base { // membres pour accéder à certains membres privates de Engine }; template<typename Engine> struct car : public car_base<Engine> { typedef car_base<Engine> base_type; void start() { // utilise les membres de base_type pour accéder // à l'interface privée de Engine } };
Je peux maintenant composer avec des types raffinés tel que advanced_car ou advanced_engine:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 struct engine { // members... // ... // OK. "car_base" est friend template<typename Engine> friend class car_base; };
En conclusion, Car peut varier indépendamment de Engine. La contrainte est que Engine reste compatible avec la façade que constitue car_base.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 template<typename Engine> struct advanced_car : public car_base<Engine> { // .. } advanced_car<engine> ac; car<advanced_engine> aac; advanced_car<advanced_engine> aaac;
Tout ceci est destiné à être utilisé dans un context plus vaste basé sur les policies. Je me fiche que advanced_car ne dérive pas de car dans l'exemple.
Est-ce que ce "trick" de la base classe paramétrée qui sera friend de son paramètre vous parait pertinent. Une autre solution ?
Partager