Je cherche à factoriser au maximum du code partagé entre plusieurs classes qui définissent des machines à états, sans utiliser d'héritage et de méthodes virtuelles. J'ai donc regardé du côté des templates, et j'en suis arrivé à me dire que le CRTP pouvait être une bonne idée pour ce faire. J'ai donc écrit un code qui ressemble vaguement à ça :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T>
class A
{
public:
        typename T::toto val;
        int a[T::nbelem];
};
 
class B : public A<B>
{
public:
        enum toto { a, b, c, nbelem };
        toto f() { return val; }
};
Le problème est que ça ne compile pas :

test.cxx: In instantiation of ‘A<B>’:
test.cxx:16: instantiated from here
test.cxx:5: error: invalid use of incomplete type ‘class B’
test.cxx:15: error: forward declaration of ‘class B’
test.cxx:6: error: incomplete type ‘B’ used in nested name specifier
test.cxx:6: error: array bound is not an integer constant
test.cxx: In member function ‘B::toto B::f()’:
test.cxx:19: error: ‘val’ was not declared in this scope
Je peux contourner ce problème en "sortant" la définition de mon enum dans une autre classe, et en écrivant le code suivant (je n'ai pas touché à A) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
class paramB
{
public:
        enum toto { a, b, c, nbelem };
};
 
class B : public A<paramB>
{
public:
        paramB::toto f() { return val; }
};
Ça me convient bien, et je pense que je vais faire comme ça. Par contre, j'aimerai bien comprendre pourquoi le premier code ne compile pas. Si quelqu'un a une explication...