Avis sur un problème de "friend class template"
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:
Code:
1 2 3 4 5 6
| template<typename T>
struct A
{
// illegal. "T" est un template argument
friend class T;
}; |
Maintenant si T est lui même paramétré par rapport à A, ça ne va pas arranger les choses.
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 :mrgreen:
Code:
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;
} |
Ce que je souhaiterais faire pour la class engine est ceci:
Code:
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;
}; |
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).
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:
Code:
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
}
}; |
- le type paramétré car_base est déclaré friend de engine:
Code:
1 2 3 4 5 6 7 8
| struct engine
{
// members...
// ...
// OK. "car_base" est friend
template<typename Engine> friend class car_base;
}; |
Je peux maintenant composer avec des types raffinés tel que advanced_car ou advanced_engine:
Code:
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; |
En conclusion, Car peut varier indépendamment de Engine. La contrainte est que Engine reste compatible avec la façade que constitue car_base.
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 ?