Cette présentation a pour but de présenter quelques notions de base des templates C++ dans le but de faire de la metaprogrammation. Au programme : spécialisation, récursion, template variadique et un exemple de polymorphisme statique.
Une autre présentation devrait permettre d'approfondir un peu.
Cette présentation a été donnée lors des Rencontres C++ à Montpellier le 16/12/14.
http://fgalinier.fr/index.html
1. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Introduction à la metaprogrammation
Florian Galinier
16 décembre 2014
2. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
• Du grec µετ ´α (après, au-delà de)
• Metalangage : Langage qui permet de décrire un autre
langage, moins abstrait.
• Rendu possible grâce à C++98 et aux templates
• Développé grâce à C++11
3. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Cette écriture abstraite :
template <typename T>
void f(T i) {
std ::cout <<i<<std:: endl;
}
4. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Correspond à cette écriture concrète :
void f(int i) {
std ::cout <<i<<std:: endl;
}
void f(float i) {
std ::cout <<i<<std:: endl;
}
void f(char i) {
std ::cout <<i<<std:: endl;
}
...
5. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Prenons un exemple un peu plus concret :
template <typename T>
T my_max(T i,T j) {
return i>=j?i:j;
}
Et pour std::string ?
6. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
string i = "ada";
string j = "c";
cout <<
my_max(i,j)
<<endl;
Et sa sortie :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
c
7. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
template <>
string my_max(string i,string j) {
return i.size ()==j.size ()?
(i>j?i:j):
(i.size()>j.size ()?i:j);
}
8. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
string i = "ada";
string j = "c";
cout <<
my_max(i,j)
<<endl;
Et sa sortie :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
ada
9. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
template <typename T,typename F>
struct is_same {
static const bool value = false;
};
10. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
string i = "ada";
cout <<
is_same <decltype(i),int >:: value
<<endl;
cout <<
is_same <decltype(i),string >:: value
<<endl;
Donnera :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
0
0
11. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
template <typename T>
struct is_same <T,T> {
static const bool value = true;
};
12. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
string i = "ada";
cout <<
is_same <decltype(i),int >:: value
<<endl;
cout <<
is_same <decltype(i),string >:: value
<<endl;
Donnera :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
0
1
13. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Petite devinette
A *b = new B();
cout <<
is_same <decltype (*b),B&>:: value
<<endl;
Que va-t-il afficher ?
14. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Réponse
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
0
15. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
(defun my_pow (x n)
(if (= n 0)
1.0
(* x (my_pow (x (- n 1))))))
16. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
template <int N>
float my_pow(float x) {
return x * my_pow <N - 1>(x);
}
template <>
float my_pow <0>( float x) {
return 1.0;
}
17. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
int main () {
float x = my_pow <3 >(3);
}
-> my_pow <3 >(3)
-> 3*my_pow <2 >(3)
-> 3*3* my_pow <1 >(3)
-> 3*3*3* my_pow <0 >(3)
-> 3*3*3*1
-> 27
18. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
struct empty_tlist {};
template <typename T,typename S>
struct tlist {
T first;
S tail;
};
19. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Avant C++11
tlist <int ,tlist <double ,tlist <float ,tlist <char ,empty_tlist > > > > t;
20. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
struct empty_tlist {};
template <typename T, typename ... S>
struct tlist {
T first;
tlist <S...> tail;
};
template <typename T>
struct tlist <T> {
T first;
};
21. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Depuis C++11
Sans variadique :
tlist <int ,tlist <double ,tlist <float ,tlist <char ,empty_tlist >>>> t;
Avec variadique :
tlist <int ,double ,float ,char ,empty_list > t;
Analysons
Avec les variadiques, nous avons la structure tlist qui est
initialisée avec les paramètres
< int, {double, float, char, empty_list} >, qui a pour tête un
int et pour queue une tlist paramétrée par
< double, float, char, empty_list >, qui est donc construite
selon les paramètres < double, {float, char, empty_list} >, etc.
22. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Que va afficher ce programme ?
class A {
public:
void foo() {
std::cout <<"A"<<std :: endl;
};
};
class B : virtual public A {
public:
void foo() {
std::cout <<"B"<<std :: endl;
};
};
int main () {
A* a = new B();
a->foo ();
}
23. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Réponse :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
A
Petite explication
L’héritage de foo étant statique, c’est le type statique de a qui
est pris en compte pour l’envoie de message foo.
24. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Que va afficher ce programme ?
class A {
public:
virtual void foo() {
std::cout <<"A"<<std :: endl;
};
};
class B : virtual public A {
public:
void foo() {
std::cout <<"B"<<std :: endl;
};
};
int main () {
A* a = new B();
a->foo ();
}
25. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Réponse :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
B
Petite explication
L’héritage de foo est maintenant déclaré comme virtual, c’est à
dire dynamique, c’est le type dynamique de a qui est donc pris
en compte pour l’envoie de message foo.
26. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Que va afficher ce programme ?
template <typename T>
class A_ {
public:
void foo() {
static_cast <T&>(* this ). foo ();
};
};
class A : public A_ <A> {
public:
void foo() {
std::cout <<"A"<<std :: endl;
};
};
class B : public A_ <B>, public A {
public:
void foo() {
std::cout <<"B"<<std :: endl;
};
};
int main () {
A_ <B> *a = new B();
a->foo ();
}
27. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
Réponse :
ynigvi@ynigvi -desktop :~/ Meetup -C++/ metaprogrammation$ ./a.out
B
Petite explication
Comme lors de l’exemple préliminaire, c’est le type statique de
a qui est pris en compte, donc de type A_. Mais A_ :: foo()
appelle foo de T, le type qui paramétrise la classe A_, c’est à
dire B, qui est également le type dynamique de a.
28. Introduction à
la metapro-
grammation
Florian
Galinier
Metaquoi ?
Introduction trop
abstraite
Un exemple plus
parlant
Allons un peu
plus loin
La spécialisation
totale
La spécialisation
partielle
La récursion
Un ajout de
C++11 : Les
templates variadiques
Un problème
d’héritage
Petite question
préliminaire
Une solution à
l’exécution
Une solution à la
compilation
Conclusion
La metaprogrammation en C++ c’est :
• avec les templates ;
• Turing-complète ;
• bien plus encore...
template <typename ... T>
void print_loop(tlist <T...> l) {
cout <<l.first;
print_loop(l.tail );
};
template <>
void print_loop <empty_list >(tlist <empty_list > l) {
cout <<endl;
};
int main () {
tlist <char ,char ,char ,char ,char ,char ,char ,char ,empty_list >
j = {’M’,’E’,’T’,’A’,’-’,’C’,’+’,’+’ ,{}};
print_loop(j);
}