Je suis en train de lire le design C++ moderne d'Andrei Alexandrescu et j'essaie d'utiliser certains des exemples de liste de types qu'il a donnés. Dans l'exemple ci-dessous, je veux créer une liste de struct Option
qui contient un type et un entier. Plus tard, je veux créer une liste de types de ces options, puis passer à une autre struct FindTypeForMapping
avec un entier. Si l'entier correspond à l'un des entiers définis dans la liste des options, l'expression doit alors correspondre au type de cette option, sinon elle doit correspondre à mon type personnalisé NullType
.Utilisation du pack de paramètres de template au lieu de la macro
Première approche qui fonctionne est que le OptionsList
est créé avec des macros, et je macros pour chaque numéro de Option
s que la liste contient, où chaque macro utilise la macro pour n
Option
s pour n-1
Option
s. Puis j'ai voulu utiliser un pack de paramètres dans les paramètres du template pour la liste. Cette version de la liste est nommée OptionsList2
. Dans OptionsList2
je récursivement construire la liste, mais ensuite j'obtiens une erreur de temps de compilation (voir ci-dessous) lors du passage de cette liste à FindTypeForMapping
.
struct NullType { };
template<class T, class U>
struct OptionsList
{
typedef T Head;
typedef U Tail;
};
template<class T, class... U>
struct OptionsList2
{
typedef T Head;
typedef typename std::conditional<sizeof...(U) == 0, NullType, OptionsList2<U...>>::type Tail;
};
template<int n, typename N>
struct Option
{
enum {
int_mapping = n
};
typedef N MappedType;
};
template<int, int> struct CheckMappedInt;
template<int n>
struct CheckMappedInt<n, n>
{
enum { is_the_same = 1};
};
template<int n, int m>
struct CheckMappedInt
{
enum { is_the_same = 0};
};
template<typename OLT, int n> struct FindTypeForMapping;
template<int n>
struct FindTypeForMapping<NullType, n>
{
typedef NullType mapped_type;
};
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList<OP, Tail>, n>
{
private:
enum {temp = CheckMappedInt<OP::int_mapping, n>::is_the_same };
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
public:
typedef typename std::conditional<
temp == 1,
typename OP::MappedType,
temp_type>::type mapped_type;
};
// Added this after SoryTellers comment
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList2<OP, Tail>, n>
{
private:
enum {temp = CheckMappedInt<OP::int_mapping, n>::is_the_same };
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
public:
typedef typename std::conditional<
temp == 1,
typename OP::MappedType,
temp_type>::type mapped_type;
};
#define OPTION_LIST_1(op1) OptionsList<op1, NullType>
#define OPTION_LIST_2(op1, op2) OptionsList<op1, OPTION_LIST_1(op2)>
#define OPTION_LIST_3(op1, op2, op3) OptionsList<op1, OPTION_LIST_2(op2, op3)>
#define OPTION_LIST_4(op1, op2, op3, op4) OptionsList<op1, OPTION_LIST_3(op2, op3, op4)>
#define OPTION_LIST_5(op1, op2, op3, op4, op5) OptionsList<op1, OPTION_LIST_4(op2, op3, op4, op5)>
#define OPTION_LIST_6(op1, op2, op3, op4, op5, op6) OptionsList<op1, OPTION_LIST_5(op2, op3, op4, op5, op6)>
#define OPTION_LIST_7(op1, op2, op3, op4, op5, op6, op7) OptionsList<op1, OPTION_LIST_6(op2, op3, op4, op5, op6, op7)>
#define OPTION_LIST_8(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsList<op1, OPTION_LIST_7(op2, op3, op4, op5, op6, op7, op8)>
#define OPTION_LIST_9(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsList<op1, OPTION_LIST_8(op2, op3, op4, op5, op6, op7, op8, op9)>
int main(int argc, char* argv[])
{
typedef Option<1, char> o1;
typedef Option<2, int> o2;
// Works
typedef OPTION_LIST_2(o1, o2) ol;
typedef typename FindTypeForMapping<ol, 1>::mapped_type ResolvedType; // Works
typedef OptionsList2<o1, o2> ol2;
typedef typename FindTypeForMapping<ol2, 1>::mapped_type ResolvedType2;
/*
error: invalid use of incomplete type ‘struct FindTypeForMapping<Option<2, int>, 1>’
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
*/
}
Quel que soit le degré de complexité du message d'erreur, vous comprenez sûrement qu'il n'y a pas de spécialisation de 'FindTypeForMapping' qui accepte un' OptionsList2', seulement 'OptionsList'. Ce sont des modèles ** différents **! – StoryTeller
Oui, merci. J'ai ajouté une copie de 'FindTypeMapping' acceptant un' OptionsList2'. Toujours une erreur mais légèrement différente. /* erreur: utilisation non valide de type incomplet « struct FindTypeForMapping
IMO ça va mal. Au lieu de dupliquer des choses, il suffit de se concentrer sur la suppression de la macro. Ajoutez une méta-fonction 'MakeOptionList' qui expose un 'OptionsList' comme son' :: type'. Ensuite, vous allez vous débarrasser de la macro. –
StoryTeller