SlideShare uma empresa Scribd logo
1 de 560
Baixar para ler offline
Alexandre Hamez
alexandre.hamez@gmail.com
C++ 11/14
PRÉSENTATION GÉNÉRALE
C++11/14
3
• Nouveau langage
• Possiblement des gains de performance juste en recompilant
• rvalues references, move semantics
• Quelques incompatibilités avec le standard précédent, mais bien
souvent pour plus de sécurité ou de performances
• ex. un destructeur ne peut plus lever d’exception par défaut
(ce qui était déjà une mauvaise chose)
• ex. règles de conversion plus strictes dans l’initialisation
d’agrégats int tab[] = {1.0}; // compilation error
4
ranged-base for loop
auto
constexpr
static_assert
rvalues references
enum class
uniform initialization
noexcept
variadic templates
relaxed POD definition
nullptr
unrestricted unions
lambdas
decltype
trailing return type
extern template
final
override
>>
user-defined literals
alignas
alignof
5
shared_ptr
unordered_map
mutex
thread
atomic
regex
unique_ptr
bind
reference_wrapper
unordered_set
tuple
chrono
random
forward
forward_list
function
enable_if
result_of
move
array
...
Compilateurs
6
• Visual Studio 2013 (incomplet)
‣ http://msdn.microsoft.com/en-us/library/hh567368.aspx
‣ plus gros manque : constexpr
• Clang ≥ 3.3
‣ http://clang.llvm.org/cxx_status.html
• GCC ≥ 4.8
‣ https://gcc.gnu.org/projects/cxx0x.html
7
http://en.cppreference.com
C++11/14
Boucles simplifiées
9
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
for ( std::vector<int>::const_iterator cit = v.begin()
; cit != v.end(); ++cit)
{
std::cout << *cit << ',';
}
}
À l’ancienne : utilisation des itérateurs
Boucles simplifiées
10
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
for (int i : v)
{
std::cout << i << ',';
}
}
Syntaxe simplifiée
Boucles simplifiées
10
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
for (int i : v)
{
std::cout << i << ',';
}
}
Syntaxe simplifiée
écriture naturelle
Boucles simplifiées
11
{
typedef std::vector<int>::const_iterator cit_t;
for ( cit_t __begin = v.begin(), __end = v.end()
; __begin != __end; ++__begin)
{
int i = *__begin;
std::cout << i << ',';
}
}
sous le capot :
Boucles simplifiées
12
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::map<int, int>::value_type key_value : m)
{
std::cout << key_value.first << ',' << key_value.second;
}
n’importe quel conteneur fournissant des itérateurs
Boucles simplifiées
12
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::map<int, int>::value_type key_value : m)
{
std::cout << key_value.first << ',' << key_value.second;
}
n’importe quel conteneur fournissant des itérateurs
pas de ‘&’ →copie
Boucles simplifiées
13
const int tab[] = {1,2,3};
for (int x : tab)
{
std::cout << x << 'n';
}
tableaux C
Boucles simplifiées
14
• En résumé, fonctionne pour
‣ les tableaux C
‣ tous les types qui fournissent
- les fonctions membres begin(), end()
- les fonctions libres begin(type), end(type)
auto
15
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<int, int>& key_value : m)
{
// do something with key_value
}
}
où est le problème?
auto
16
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<const int, int>& key_value : m)
{
// ...
}
}
où est le problème?
auto
16
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<const int, int>& key_value : m)
{
// ...
}
}
où est le problème?
la clef dans une std::map est
constante
auto
17
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (auto& key_value : m)
{
// ...
}
}
auto
17
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (auto& key_value : m)
{
// ...
}
}
le compilateur fait le travail pour
nous : plus d’erreur possible
18
auto
#include <map>
int main()
{
auto m = std::map<int, int>();
m.insert(std::make_pair(1,1));
for (auto& key_value : m)
{
// do something with key_value
}
}
18
auto
#include <map>
int main()
{
auto m = std::map<int, int>();
m.insert(std::make_pair(1,1));
for (auto& key_value : m)
{
// do something with key_value
}
}
pour toute variable
19
auto m = std::map<int, int>();
for (const auto& key_value : m)
{
key_value.second = 2; // compilation error
}
auto
auto utilise les règles de déduction des templates
20
#include <vector>
std::vector<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const auto& value : container)
{
// do something
}
}
auto
facilite la maintenance de code
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const auto& value : container)
{
// do something
}
}
facilite la maintenance de code
auto
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const auto& value : container)
{
// do something
}
}
fun() change
facilite la maintenance de code
auto
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const auto& value : container)
{
// do something
}
}
main() ne change pas!
fun() change
facilite la maintenance de code
auto
22
• permet d’adopter un style de programmation fonctionnelle
‣ Scala : val x = fun()
‣ C++ : const auto x = fun();
• auto utilise les règles de déduction des templates
‣ sauf pour le cas des listes d’initialisation (initializer_list)
auto
23
const auto x = foo();
void* _ = x;
error: cannot initialize a variable of type 'void *' with an lvalue of type
'TYPE'
  void* _ = x;
        ^   ~
1 error generated.
auto
connaître le type déduit (tout compilateur)
Initialisation uniformisée
24
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// function declaration or variable definition?
bar b(foo());
}
“most vexing parse”
• define variable b of type bar with an instance of foo; or
• declare function b which returns a bar and takes a function with no parameter and which
returns a foo
25
Initialisation uniformisée
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// add parentheses to declare a variable
bar b((foo()));
}
“most vexing parse”
26
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// brace initializer
bar b{foo{}};
// better
auto b1 = bar{foo{}};
}
solution : utiliser la syntaxe pour initialiser les agrégats : {}
Initialisation uniformisée
27
struct foo
{
int i_;
foo(int i) : i_(i) {}
};
struct bar
{
int i_;
};
int main()
{
const auto f = foo{42};
const auto b = bar{42};
}
pour construire un objet
Initialisation uniformisée
28
class foo
{
int i_;
public:
foo(int i) : i_(i) {}
};
struct bar
{
int i_;
};
int main()
{
const auto f = foo{42};
const auto b = bar{42};
}
pour construire struct ou class
Initialisation uniformisée
29
struct foo
{
int i;
};
foo fun()
{
return {42};
}
int main()
{
const auto f = fun();
}
concision : on peut omettre le type de retour
Initialisation uniformisée
29
struct foo
{
int i;
};
foo fun()
{
return {42};
}
int main()
{
const auto f = fun();
}
concision : on peut omettre le type de retour
pas de type explicite
Initialisation uniformisée
30
#include <map>
int main()
{
auto m = std::map<int,int>{};
// old style
m.insert(std::make_pair(1, 2));
// new style
m.insert({1, 2});
}
exemple : insertion dans un conteneur associatif
Initialisation uniformisée
31
double a, b, c;
int x{a + b + c};
int y(a + b + c);
int z = a + b + c;
ne compile pas :
perte de précision
OK (mais mal)
idem
plus de sécurité
Initialisation uniformisée
32
• Que choisir?
• “{}”
‣ résistant au most vexing parse
‣ empêche la perte de précision
‣ utilisation plus cohérente
• “()”
‣ ne casse pas les habitudes
‣ pas de confusion avec initializer_list (à suivre…)
Initialisation uniformisée
initializer_list
33
#include <iostream>
#include <vector>
int main()
{
const auto vec = std::vector<int>{1,2,3};
for (const auto& x : vec)
{
std::cout << x;
}
}
même syntaxe que pour initialiser les agrégats
initializer_list
33
#include <iostream>
#include <vector>
int main()
{
const auto vec = std::vector<int>{1,2,3};
for (const auto& x : vec)
{
std::cout << x;
}
}
déclaration “naturelle”
même syntaxe que pour initialiser les agrégats
initializer_list
34
• C++11 définit un nouveau type
‣ std::initializer_list<T>
‣ #include <initializer_list>
• Utilise la même syntaxe d'initialisation des tableaux C
• {1,2,3}
• Le contenu de la liste est copié
initializer_list
35
#include <initializer_list>
int main()
{
// deduced to std::initializer_list<int>
const auto list = {1,2,2};
for (auto x : list)
{
// ...
}
}
exception : auto + {} initializer_list
auto utilise la déduction des templates
initializer_list
35
#include <initializer_list>
int main()
{
// deduced to std::initializer_list<int>
const auto list = {1,2,2};
for (auto x : list)
{
// ...
}
}
ne pas oublier!
exception : auto + {} initializer_list
auto utilise la déduction des templates
initializer_list
36
void foo(std::initializer_list<int> list)
{
for (auto i : list) {}
}
foo({1,2,3});
initializer_list en paramètre
initializer_list
36
void foo(std::initializer_list<int> list)
{
for (auto i : list) {}
}
foo({1,2,3});
passage par valeur
initializer_list en paramètre
initializer_list
37
struct bar
{
bar(std::initializer_list<int> list);
};
const auto b = bar{1,2,3};
can be used to construct objects
initializer_list
38
void foo(int i, std::initializer_list<int> li)
{
std::cout << i << " : ";
for (auto x : li) std::cout << x << ",";
}
foo(42, {3,2,3,4});
utilisable avec d’autres arguments
initializer_list
39
for (auto x : {1,2,3,4})
{
std::cout << x << ',';
}
utilisable dans une boucle simplifiée
initializer_list
40
#include <iostream>
#include <initializer_list>
struct bar
{
bar(std::initializer_list<int> list){std::cout << "listn";}
bar(int) {std::cout << "intn";}
};
int main()
{
const auto b = bar{1};
}
qu’affiche le code suivant?
initializer_list
41
#include <iostream>
#include <vector>
int main ()
{
const auto v1 = std::vector<int>{2};
std::cout << v1.size();
const auto v2 = std::vector<int>(2);
std::cout << v2.size();
}
mais… qu’affiche le code suivant?
initializer_list
42
• Permet de
‣ faciliter l’écriture des tests unitaires
‣ offrir une API élégante au code client
‣ …
const auto v1 = std::vector<int>{1,2,3};
auto v2 = std::vector<int>{};
v2.reserve(3);
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
vs
initializer_list
42
• Permet de
‣ faciliter l’écriture des tests unitaires
‣ offrir une API élégante au code client
‣ …
const auto v1 = std::vector<int>{1,2,3};
auto v2 = std::vector<int>{};
v2.reserve(3);
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
vs
bonus : plus d’immutabilité
User-defined literals
43
unsigned long x0 = 0ul;
long x1 = 0l;
// etc.
C++03 : il est possible de suffixer un littéral
pour y appliquer des caractéristiques
User-defined literals
44
long double
operator"" _deg (long double x)
{
return x * 3.141592/180;
}
const auto x = 90.0_deg;
pour convertir une valeur
User-defined literals
44
long double
operator"" _deg (long double x)
{
return x * 3.141592/180;
}
const auto x = 90.0_deg;
ne pas oublier “_”
pour convertir une valeur
User-defined literals
45
struct foo
{
const unsigned long long x_;
foo(unsigned long long x)
: x_(x)
{}
};
foo
operator"" _foo (unsigned long long n)
{
return {n};
}
const auto f = 123_foo;
pour construire un objet
User-defined literals
46
void
operator"" _print(const char* str, std::size_t)
{
std::cout << str;
}
"C++11 rocks!"_print;
à partir de chaînes de caractères
User-defined literals
47
struct point
{
//???
};
// Yaye!
const auto p = 3_x + 5_y;
comment obtenir cette construction?
User-defined literals
48
struct x_type{unsigned long long value;};
struct y_type{unsigned long long value;};
x_type operator"" _x(unsigned long long value) {return {value};}
y_type operator"" _y(unsigned long long value) {return {value};}
struct point
{
unsigned long long x_, y_;
private:
point(const x_type& x, const y_type& y)
: x_(x.value), y_(y.value)
{}
friend point operator+(const x_type&, const y_type&);
};
point operator+(const x_type& x, const y_type& y)
{return {x, y};};
// later...
const auto p = 3_x + 5_y;
String literals
49
const auto utf8 = u8"UTF-8 string. u2705n”;
std::cout << utf8;
const auto utf16 = u8"UTF-16 string.n”;
std::wcout << utf16;
UTF-8 string. ✅
UTF-16 string.
Gestion UTF-8, UTF-16 et UTF-32
Binary literals
50
const auto b = 0b00101010;
std::cout << b; // 42
C++14 uniquement
Séparateur ‘
51
const auto big_value = 64'000'000'000'000'000;
facilite la lecture des grandes constantes
const auto b = 0b0010'1010;
Raw string literals
52
const auto raw = R"(@
tLook Ma, no tabs!
some
text
)";
const auto escaped = "@n"
"somen"
"textn";
int
main()
{
std::cout << raw;
std::cout << "--------------n";
std::cout << escaped;
}
@
tLook Ma, no tabs!
some
text
--------------
@
some
text
enum class
53
int main()
{
enum e{pink, white, orange, brown};
const auto white = 0ul;
}
error: redefinition of 'white' as different kind of symbol
  const auto white = 0ul;
             ^
note: previous definition is here
  enum e{pink, white, orange, brown};
               ^
enum C++03 : pollution de l’espace de nommage
enum class
53
int main()
{
enum e{pink, white, orange, brown};
const auto white = 0ul;
}
ne compile pas
error: redefinition of 'white' as different kind of symbol
  const auto white = 0ul;
             ^
note: previous definition is here
  enum e{pink, white, orange, brown};
               ^
enum C++03 : pollution de l’espace de nommage
enum class
54
enum e {pink, white, orange, brown};
if (pink < 99.3)
{
// ...
}
enum C++03 : conversion implicite dangereuse
enum class
54
enum e {pink, white, orange, brown};
if (pink < 99.3)
{
// ...
}
enum C++03 : conversion implicite dangereuse
compile, mais est-ce
vraiment une bonne chose?
enum class
55
int main()
{
enum class e{pink, white, orange, brown};
const auto white = 0ul;
const auto e0 = e::white;
}
enum class créé une nouvelle portée
enum class
55
int main()
{
enum class e{pink, white, orange, brown};
const auto white = 0ul;
const auto e0 = e::white;
}
enum class créé une nouvelle portée
accès à la portée de e
enum class
56
enum class e{pink, white, orange, brown};
// use std::underlying_type<e>::type to find enum’s type
type par défaut sous-jacent : int
enum class
57
enum class e : unsigned long
{pink = 0, white, orange, brown = 0xFFFFFFFFFFFFFFFF};
// use std::underlying_type<e>::type to find enum’s type
changer le type sous-jacent
enum class
58
• C++03 : il n’y a pas de type par défaut pour énumération
‣ on est donc obligé de la mettre dans les headers
‣ recompilation en cascade s’il faut rajouter un champ
• C++11 : on peut faire une pré-déclaration
‣ définition dans une unité de compilation séparée
‣ pas de recompilation en cascade
nullptr
59
void f(int) {std::cout << "f(int)";}
void f(void*){std::cout << "f(void*)";}
f(0);
f(NULL);
error: call to 'f' is ambiguous
  f(NULL);
  ^
note: candidate function
void f(int)  {std::cout << "f(int)";}
     ^
note: candidate function
void f(void*){std::cout << "f(void*)";}
f(int)
f(int)
clang/gcc Visual Studio
nullptr
60
void f(int) {std::cout << "f(int)";}
void f(void*){std::cout << "f(void*)";}
f(0);
f(nullptr);
f(int)
f(void*)
moins d’ambiguité
nullptr
61
const auto x = f();
if (x == 0)
{
// ...
}
plus de clarté
const auto x = f();
if (x == nullptr)
{
// ...
}
vs
nullptr
61
const auto x = f();
if (x == 0)
{
// ...
}
plus de clarté
const auto x = f();
if (x == nullptr)
{
// ...
}
vs intention plus claire
nullptr
62
type de nullptr
void f(int) {std::cout << "f(int)";}
void f(void*) {std::cout << "f(void*)";}
void f(std::nullptr_t) {std::cout << "f(nullptr_t)";}
f(nullptr);
alignas
63
alignas(16) int a;
alignas(32768) int b;
std::cout << &a;
std::cout << &b;
0x7fff58d2ffe0
0x7fff58d28000
contrôler l’alignement mémoire
alignof
64
std::cout << alignof(int);
std::cout << alignof(long);
std::cout << alignof(char);
std::cout << alignof(char*);
connaître l’alignement mémoire (d’un type)
4
8
1
8
Classes
• Délégation de constructeurs
• Héritage des constructeurs des classes de base
• Initialisation directe des attributs
• Contrôle de l’héritage
• Contrôle explicite des méthodes supprimées
65
Classes
66
délégation de constructeurs (1)
struct foo
{
const int x_;
foo(int x)
: x_{x}
{}
foo()
: foo{42}
{}
};
Classes
66
délégation de constructeurs (1)
struct foo
{
const int x_;
foo(int x)
: x_{x}
{}
foo()
: foo{42}
{}
};
délégation
Classes
67
délégation de constructeurs (2)
struct foo
{
const int x_;
foo(int x = 42)
: x_{x}
{}
};
on pourrait utiliser les arguments par défaut
problème : dans l’interface de la classe
Classes
68
héritage des constructeurs (1) : C++03
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : public base
{
foo(int x)
: base(x)
{}
};
Classes
68
héritage des constructeurs (1) : C++03
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : public base
{
foo(int x)
: base(x)
{}
};
appel explicite
Classes
69
héritage des constructeurs (2) : C++11
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : public base
{
using base::base;
};
Classes
69
héritage des constructeurs (2) : C++11
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : public base
{
using base::base;
};
hérite de tous les constructeurs
de base
Classes
70
initialisation directe des attributs
struct foo
{
const int x_ = 33;
foo(int x)
: x_(x)
{}
foo()
{}
};
Classes
70
initialisation directe des attributs
struct foo
{
const int x_ = 33;
foo(int x)
: x_(x)
{}
foo()
{}
};
valeur par défaut utilisée par tous
les constructeurs
Classes
71
contrôle de l’héritage avec final
struct foo final {};
struct bar : foo {};
Classes
71
contrôle de l’héritage avec final
struct foo final {};
struct bar : foo {};
ne compile pas
error: base 'foo' is marked 'final'
struct bar : foo {};
             ^
Classes
72
contrôle de l’héritage avec override (1)
struct base
{
virtual void operator()(float x) const
{std::cout << "base " << x;}
};
struct derived : public base
{
virtual void operator()(int x) const
{std::cout << "derived " << x;}
};
const auto d = derived{};
auto x = 33.3;
d(x);
Classes
72
contrôle de l’héritage avec override (1)
struct base
{
virtual void operator()(float x) const
{std::cout << "base " << x;}
};
struct derived : public base
{
virtual void operator()(int x) const
{std::cout << "derived " << x;}
};
const auto d = derived{};
auto x = 33.3;
d(x);
affichage?
Classes
73
contrôle de l’héritage avec override (2)
struct base
{
virtual void operator()(float x) const;
};
struct derived : public base
{
virtual void operator()(int x) const override;
};
Classes
73
contrôle de l’héritage avec override (2)
struct base
{
virtual void operator()(float x) const;
};
struct derived : public base
{
virtual void operator()(int x) const override;
};
error: 'operator()' marked 'override' but does not override any member functions
  virtual void operator()(int x) const
               ^
Classes
74
contrôle des fonctions membres avec default / delete (1)
struct non_copyable
{
non_copyable(){}
private:
non_copyable(const non_copyable&);
non_copyable& operator=(const non_copyable&);
};
int main()
{
const auto nc = non_copyable{};
}
error: calling a private constructor of class 'non_copyable'
  const auto nc = non_copyable{};
                  ^
Classes
75
struct non_copyable
{
non_copyable() = default;
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
};
int main()
{
const auto nc = non_copyable{};
}
error: call to deleted constructor of 'const non_copyable'
  const auto nc = non_copyable{};
             ^    ~~~~~~~~~~~~~~
note: 'non_copyable' has been explicitly marked deleted here
  non_copyable(const non_copyable&) = delete;
contrôle des fonctions membres avec default / delete (2)
Classes
76
struct base
{
virtual void operator()(int x) const;
};
struct derived : public base
{
virtual void operator()(int x) const override;
};
int main()
{
const auto override = 0ul;
const auto final = 0ul;
}
contrôle des fonctions membres avec default / delete (3)
Classes
76
struct base
{
virtual void operator()(int x) const;
};
struct derived : public base
{
virtual void operator()(int x) const override;
};
int main()
{
const auto override = 0ul;
const auto final = 0ul;
}
pas des mots-clefs
contrôle des fonctions membres avec default / delete (3)
delete
77
void foo(int){};
void foo(long) = delete;
void foo(double) = delete;
foo(42); // OK
foo(42l); // ERROR
foo(42.0); // ERROR
permet aussi d’empêcher certaines surcharges
error: call to deleted function 'foo'
  foo(42l);
  ^~~
note: candidate function has been explicitly deleted
void foo(long) = delete;
     ^
note: candidate function
void foo(int){};
     ^
note: candidate function has been explicitly deleted
void foo(double) = delete;
     ^
Rvalues references
• Ajout majeur au C++
• Travailler explicitement avec les temporaires
• Éviter des copies inutiles
‣ move semantics
• Perfect forwarding
‣ construire en place
‣ généricité améliorée
‣ …
78
Rvalues references
• lvalues
‣ un objet qui occupe une place identifiable en mémoire
- qui a une adresse
• rvalues
‣ un objet qui n’occupe pas une place identifiable en mémoire
- qui n’a pas d’adresse : temporaire
79
lvalue = rvalue
lvalue = lvalue
rvalue = lvalue
int x = 42
int x = y
42 = ...
Rvalues references
80
int foo() {return 2;}
int main()
{
foo() = 2;
}
error: lvalue required as left operand of assignment
foo() = 2;
^
Rvalues references
81
struct foo {
foo() {
std::cout << “foo()n”;
}
foo(const foo&) {
std::cout << "foo(const foo&)n”;
}
foo& operator=(const foo&) {
std::cout << "operator=(const foo&)n”;
return *this;
}
};
foo bar() {return {};}
const auto f0 = foo{};
auto f1 = bar();
f1 = bar();
interlude : copy elision
Rvalues references
81
struct foo {
foo() {
std::cout << “foo()n”;
}
foo(const foo&) {
std::cout << "foo(const foo&)n”;
}
foo& operator=(const foo&) {
std::cout << "operator=(const foo&)n”;
return *this;
}
};
foo bar() {return {};}
const auto f0 = foo{};
auto f1 = bar();
f1 = bar();
interlude : copy elision
?
Rvalues references
82
comment éviter la copie? (1)
foo* bar() {return new foo{};}
auto f1 = bar();
// later...
f1 = bar();
• Retour par pointeur
‣ Coût de l’allocation
‣ Qui est responsable du pointeur?
Rvalues references
83
comment éviter la copie? (2)
void bar(foo*);
auto f = foo{};
bar(&f);
• Passage par pointeur ou référence en paramètre
• Quid des factories?
Rvalues references
84
comment modifier un temporaire?
void bar(foo&);
//...
auto f = foo{};
bar(f1);
bar(foo{});
utile pour un objet fonction avec état (cache, etc.)
Rvalues references
84
comment modifier un temporaire?
void bar(foo&);
//...
auto f = foo{};
bar(f1);
bar(foo{}); ne compile pas
utile pour un objet fonction avec état (cache, etc.)
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalue reference
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalue reference
foo{42} : rvalue expression
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalue reference
foo{42} : rvalue expression
f : lvalue expression
on peut prendre l’adresse de f
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalue reference
foo{42} : rvalue expression
f : lvalue expression
on peut prendre l’adresse de f
le passage en paramètre “nomme” le temporaire
celui-ci devient une lvalue : on peut prendre son adresse sur la pile
Rvalues references
86
une rvalue reference n’accepte que des rvalue expressions
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
auto f = foo{42};
bar(f);
Rvalues references
86
une rvalue reference n’accepte que des rvalue expressions
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
auto f = foo{42};
bar(f);
erreur : f n’est pas une rvalue expression
Rvalues references
87
ref-qualifiers
struct foo
{
void operator()() const
&&
{
std::cout << "&&n";
}
void operator()() const
&
{
std::cout << "&n";
}
};
//...
const auto f = foo{};
f();
foo{}();
Rvalues references
87
ref-qualifiers
struct foo
{
void operator()() const
&&
{
std::cout << "&&n";
}
void operator()() const
&
{
std::cout << "&n";
}
};
//...
const auto f = foo{};
f();
foo{}();
en tant que
rvalue
en tant que
lvalue
Move semantics
• Permet d’exprimer le “déplacement” d’une ressource
• Permet d’exprimer le changement de propriétaire d’une entité
non copiable
‣ mutex, fichier, …
• Utilisation des rvalues references
• Utilisation de std::move()
‣ instruction au compilateur
‣ ne génère aucun code
88
Ressource2Ressource1
Move semantics
89
A B
X Ressource1
Move semantics
89
A B
Move semantics
90
struct foo {
some_type* ressource;
foo& operator=(const foo& rhs) {
// destroy this->ressource
// clone rhs.ressource
// attach this cloned ressource to this->ressource
}
};
auto f1 = foo{};
auto f2 = foo{};
// later...
f2 = f1;
copie
Move semantics
90
struct foo {
some_type* ressource;
foo& operator=(const foo& rhs) {
// destroy this->ressource
// clone rhs.ressource
// attach this cloned ressource to this->ressource
}
};
auto f1 = foo{};
auto f2 = foo{};
// later...
f2 = f1;
copie
O(n)
Move semantics
91
auto f1 = foo{};
//...
auto f2 = std::move(f1);
// now f1 is “invalid”
transfert de ressource (1)
move() transforme une lvalue expression en rvalue expression
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.ressource pointer to this->ressource
}
};
auto f1 = foo{};
auto f2 = foo{};
//...
f2 = std::move(f1);
transfert de ressource (2)
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.ressource pointer to this->ressource
}
};
auto f1 = foo{};
auto f2 = foo{};
//...
f2 = std::move(f1);
transfert de ressource (2)
O(1)
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.ressource pointer to this->ressource
}
};
auto f1 = foo{};
auto f2 = foo{};
//...
f2 = std::move(f1);
transfert de ressource (2)
O(1) mais pas toujours…
Move semantics
93
struct foo
{
foo() = default;
foo(const foo&) = default;
foo(foo&&) = delete;
};
int main()
{
const auto f = foo{};
}
Move semantics
93
struct foo
{
foo() = default;
foo(const foo&) = default;
foo(foo&&) = delete;
};
int main()
{
const auto f = foo{};
}
ne compile pas
Move semantics
94
struct foo {};
foo return_by_value()
{
const auto f = foo{};
return f;
}
void take_by_value(foo) {}
auto f1 = foo{};
auto f2 = f1;
auto f3 = std::move(f1);
take_by_value(f2);
take_by_value(std::move(f2));
auto f4 = return_by_value();
f1 = return_by_value();
quelles sont
les opérations
appelées?
Move semantics
95
transfert de propriété
struct foo
{
some_type ressource;
// forbid copy
foo(const foo&) = delete;
foo& operator=(const foo&) = delete;
foo(foo&& rhs) noexcept
{
// 1. acquire ownership of rhs.ressource
// 2. free rhs from its ownership
}
foo& operator=(foo&&) noexcept
{
// 1. release ownership of current ressource
// 2. acquire ownership of rhs.ressource
// 3. free rhs from its ownership
}
};
Move semantics
96
struct foo;
foo bar()
{
auto f = foo{};
// later...
return std::move(f);
}
std::move en retour d’une fonction
Move semantics
96
struct foo;
foo bar()
{
auto f = foo{};
// later...
return std::move(f);
}
mauvaise idée
std::move en retour d’une fonction
Move semantics
97
const rvalue references?
void bar(const foo&& f); // what for if we can't move f?
void bar(const foo&); // read only
réellement utile pour interdire tout usage des rvalues
struct foo
{
foo() {};
foo(foo&&) = delete;
foo(const foo&&) = delete;
};
// later...
const foo f0;
foo f1(std::move(f0));
void bar(const foo&& f); // what for if we can't move f?
void bar(const foo&); // read only
Move semantics
98
struct foo;
foo f1;
foo f2;
std::swap(f1, f2);
C++03 vs C++11
foo()
foo()
foo(foo&&)
operator=(foo&&)
operator=(foo&&)
foo()
foo()
foo(const foo&)
operator=(const foo&)
operator=(const foo&)
C++03 C++11
decltype
99
permet de connaître le type d’une expression
int* foo();
using ty0 = decltype(foo);
print_type<ty0>();
using ty1 = decltype(foo());
print_type<ty1>();
void print_type() [T = int *()]
void print_type() [T = int *]
trailing return type
100
auto foo() -> int
{
return 42;
}
std::cout << foo();
type de retour après les paramètres
trailing return type
101
template <typename T1, typename T2>
???
add(const T1& x, const T2& y)
{
return x + y;
}
si le type de retour dépend des paramètres
template <typename T1, typename T2>
auto
add(const T1& x, const T2& y)
-> decltype(x+y)
{
return x + y;
}
trailing return type
102
double (*get_fun2(bool arg))(double)
{
if (arg) return std::cos;
else return std::sin;
}
plus de lisibilité
auto get_fun(bool arg)
-> double(*)(double)
{
if (arg) return std::cos;
else return std::sin;
}
vs
trailing return type
103
C++14 : on peut se passer du type de retour
template <typename T1, typename T2>
auto
add(const T1& x, const T2& y)
-> decltype(x+y)
{
return x + y;
}
trailing return type
104
C++14 : on peut se passer du type de retour
mais pas toujours…
auto get_fun(bool arg)
{
if (arg) return std::cos;
else return std::sin;
}
error: cannot deduce return type 'auto' from returned value of type '<overloaded
function type>'
  if (arg) return std::cos;
105
lambdas
struct print1
{
void operator()(int x) const
{
std::cout << x << 'n';
}
};
void print2(int x)
{
std::cout << x << 'n';
}
const auto v = {1,2,3};
std::for_each(begin(v), end(v), print1{});
std::for_each(begin(v), end(v), print2);
programmation fonctionnelle :
objets fonctions et fonctions en argument
lambdas
106
const auto v = {1,2,3};
std::for_each( begin(v), end(v)
, [](int x){std::cout << x << ‘n';}
);
const auto v = {1,2,3};
const auto print =
[](int x){std::cout << x << 'n';};
std::for_each(begin(v), end(v), print);
par l’exemple
const auto fun = []{return 42;};
const auto x = fun();
std::cout << x << 'n';
lambdas
107
const auto print = [](int x){std::cout << x;};
print_type<decltype(print)>();
void print_type() [with T = const main()::<lambda(int)>]
type d’un lambda
il n’y pas de type pour les lambdas en tant que tel
auto est quasi-obligatoire si on veut stocker un lambda
ou presque…
lambdas
108
anatomie d’un lambda
[capture](params) -> ret_type {body}
comment “capturer”
l’environnement corps de la fonction
peut-être omis
type de retour si nécessaire
lambdas
109
spécification du type de retour (1)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
const auto foo_maker = [](bool value)
{
if (value) return new bar{};
else return new baz{};
};
const auto ptr = foo_maker(true);
error: return type 'baz *' must match previous return type 'bar *' when lambda
expression has unspecified explicit return type
                             else       return new baz{};
                                        ^
lambdas
110
spécification du type de retour (2)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
const auto foo_maker = [](bool value) -> foo*
{
if (value) return new bar{};
else return new baz{};
};
const auto ptr = foo_maker(true);
lambdas
110
spécification du type de retour (2)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
const auto foo_maker = [](bool value) -> foo*
{
if (value) return new bar{};
else return new baz{};
};
const auto ptr = foo_maker(true);
type de retour
lambdas
111
capture de l’environnement (1)
[] ne capture rien
[&] tout par référence
[=] tout par valeur
[this] capture this
[=,&b]
copie tout, mais
reférence b
[&a, b] référence a, copie b
environnement = toutes les variables de la portée englobante
lambdas
111
capture de l’environnement (1)
[] ne capture rien
[&] tout par référence
[=] tout par valeur
[this] capture this
[=,&b]
copie tout, mais
reférence b
[&a, b] référence a, copie b
environnement en
“lecture seule”
environnement = toutes les variables de la portée englobante
const auto x = 42u;
[]{std::cout << x;}(); // OK
auto x = 40u;
[]{x += 2;}(); // ERROR
struct foo
{
int x_;
int bar(int y)
{
return [this](int y)
{return x_ + y;}
(y);
}
};
std::cout << foo{40}.bar(2);
lambdas
112
auto x = 40u;
[&x](int y){x += y;}(2);
std::cout << x;
auto a = 40u;
[&](int b){a += b;}(2);
std::cout << x;
capture de l’environnement (2)
struct foo
{
int x_;
int bar(int y)
{
return [this](int y)
{return x_ + y;}
(y);
}
};
std::cout << foo{40}.bar(2);
lambdas
112
auto x = 40u;
[&x](int y){x += y;}(2);
std::cout << x;
auto a = 40u;
[&](int b){a += b;}(2);
std::cout << x;
capture de l’environnement (2)
auto x = 44u;
[=]{x -= 2;}();
lambdas
113
error: cannot assign to a variable captured by copy in a non-mutable lambda
  [=]{x -= 2;}();
      ~ ^
auto x = 44u;
[=]() mutable {x -= 2;}();
capture de l’environnement (3)
auto x = 44u;
[=]{x -= 2;}();
lambdas
113
error: cannot assign to a variable captured by copy in a non-mutable lambda
  [=]{x -= 2;}();
      ~ ^
auto x = 44u;
[=]() mutable {x -= 2;}();
obligatoire
capture de l’environnement (3)
lambdas
114
“fermeture” équivalente à un objet fonction (1)
struct closure
{
double& capture_;
int operator()(int x, int& y) const
{
return (x + y) * capture_;
}
closure() = delete;
closure& operator=(const closure&) = delete;
closure(const closure& ) = default;
closure(closure&& ) = default;
~closure() = default;
};
auto fun0 = [&d](int x, int& y){return (x + y) * d;};
lambdas
114
“fermeture” équivalente à un objet fonction (1)
struct closure
{
double& capture_;
int operator()(int x, int& y) const
{
return (x + y) * capture_;
}
closure() = delete;
closure& operator=(const closure&) = delete;
closure(const closure& ) = default;
closure(closure&& ) = default;
~closure() = default;
};
auto fun0 = [&d](int x, int& y){return (x + y) * d;};
d’où le mutable
lambdas
115
auto d = 0.0;
auto fun1 = fun0; // OK
fun1 = fun0; // KO no copy operator
using ty = decltype(fun0);
auto fun2 = ty{}; // KO no default ctor
auto fun0 = [&d](int x, int& y){return (x + y) * d;};
“fermeture” équivalente à un objet fonction (2)
lambdas
116
en paramètre d’un template
template <typename F, typename T>
void apply(T x)
{
F{}(x);
}
auto fun = [](int x){x += 1;};
apply<decltype(fun)>(0);
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int& j){j += i;};
}
int main()
{
auto j = 2;
const auto fun = mk_fun();
fun(j); // Doomed to failure
}
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int& j){j += i;};
}
int main()
{
auto j = 2;
const auto fun = mk_fun();
fun(j); // Doomed to failure
}
portée locale à mk_fun
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int& j){j += i;};
}
int main()
{
auto j = 2;
const auto fun = mk_fun();
fun(j); // Doomed to failure
}
portée locale à mk_fun
lecture de i locale à
mk_fun
lambdas
118
C++14 : paramètres génériques
const auto add
= [](const auto& x, const auto& y){return x + y;};
add(1,2);
add(std::string{"1"}, std::string{"2"});
lambdas
119
au service de l’immutabilité
const auto read_only = [&]
{
std::vector<int> res;
// super-complex initialisation
return res
}();
read_only.push_back(3); // nope, won’t do
auto read_only = std::vector<int>{};
// super-complex initialisation
// ...later
// damned, still mutable!
read_only.push_back(3);
noexcept
• C++03
‣ il faut lister dans la signature d’une fonction les exceptions qu’elle
peut lever (throw (…))
‣ difficile à maintenir
‣ pas ou peu d’aide des compilateurs
• C++11
‣ seule alternative : une fonction peut ou ne peut pas lever
d’exception
‣ avantage majeur : le compilateur a plus d’opportunités
d’optimisations
120
noexcept
121
void foo()
noexcept
{
// shall not throw any exception
}
struct foo
{
void
operator()() const
noexcept
{
// shall not throw any exception
}
};
sur fonctions libres ou membres
noexcept
122
opportunités d’optimisation
auto vec = std::vector<foo>{};
const auto f = foo{};
vec.push_back(f);
• Si vec doit agrandir son stockage interne
‣ C++03 : recopie
- si une exception est lancée pendant la copie, vec original n’est pas
modifié (strong guarantee)
‣ C++11 : strong guarantee à tenir
- move si foo(foo&&) noexcept
- copie sinon
noexcept
123
noexcept conditionnel (1)
void bar()
noexcept
{
// shall not throw any exception
}
void foo()
noexcept(noexcept(bar()))
{
bar();
}
noexcept
124
noexcept conditionnel (2)
struct bar
{
void operator()(int) noexcept {}
};
struct baz
{
void operator()(int){}
};
template <typename Fun>
void foo(int x)
noexcept(noexcept(Fun{}(x)))
{
Fun{}(x);
}
foo<bar>(33);
foo<baz>(42);
noexcept
125
noexcept appliqué aux lambdas
const auto lambda
= [](int x) noexcept {return x + 40;};
std::cout << lambda(2);
• Destructeurs, operator delete et operator delete[] : noexcept par
défaut
• C’est une affirmation forte
‣ déclarer une fonction noexcept, puis plus tard enlever cette spécification
peut casser le code client
• Important pour
‣ foo(foo&&)
‣ foo& operator=(foo&&)
‣ swap(foo&, foo&)
‣ fonctions de calcul (sans allocations dynamiques)?
‣ …?
126
noexcept
constexpr
127
• const : spécifier des interfaces
- foo(const std::vector<int>&);
• constexpr : spécifier ce qui est utilisable dans des expressions
constantes (et donc possiblement évaluées à la compilation)
- tout ce qui est marqué constexpr doit pouvoir produire
un résultat constant
• Applicable aux objets et aux fonctions
Visual Studio 2013
constexpr
128
auto sz = 3;
// ERROR: sz's value not known at compilation
constexpr auto sz1 = sz;
// ERROR: sz's value not known at compilation
auto array1 = std::array<int, sz>{};
// OK: 10 is a compile-time constant
constexpr auto sz2 = 10;
// OK: sz2 is constexpr
auto array2 = std::array<int, sz2>{};
objets (1)
constexpr
129
const auto sz = 3;
// OK: sz's value is known at compilation
constexpr auto sz1 = sz;
// OK: sz's value is known at compilation
auto array1 = std::array<int, sz>{};
auto x = 3;
const auto sz = x;
// ERROR: sz's value not known at compilation
constexpr auto sz1 = sz;
// ERROR: sz's value not known at compilation
auto array1 = std::array<int, sz>{};
objets (2)
constexpr
130
fonctions
constexpr
int foo(int a)
{
return a + 1;
}
constexpr auto x = foo(42);
auto runtime_value = 0u;
std::cin >> runtime_value;
auto y = foo(runtime_value);
fonction expression constante expression non-constante
constexpr ✓ ✓
non-constexpr ✕ ✓
constexpr
131
C++11
seulement une expression autorisée
constexpr int fac(int x)
{
return x <= 1
? 1
: x * fac(x-1);
}
constexpr int fac(int x)
{
auto res = 1;
for (auto i = 1; i <= x; ++i)
{
res *= i;
}
return res;
}
C++14
plusieurs instructions autorisées
constexpr
132
classes
struct foo
{
int data;
constexpr foo(int d) : data(d) {}
constexpr int operator()() const
{return data + 1;}
constexpr operator int() const
{return data;}
};
auto f0 = foo{42};
constexpr auto f1 = foo{33};
auto i0 = f0();
constexpr auto i1 = f1();
constexpr auto i2 = static_cast<int>(f1);
auto i3 = static_cast<int>(f1);
constexpr
132
classes
struct foo
{
int data;
constexpr foo(int d) : data(d) {}
constexpr int operator()() const
{return data + 1;}
constexpr operator int() const
{return data;}
};
auto f0 = foo{42};
constexpr auto f1 = foo{33};
auto i0 = f0();
constexpr auto i1 = f1();
constexpr auto i2 = static_cast<int>(f1);
auto i3 = static_cast<int>(f1);
implicite en C++11
à mettre en C++14
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
en pratique (clang)…
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
pushq %rbp
movq %rsp, %rbp
movl $0x78, %eax
popq %rbp
retq
en pratique (clang)…
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
pushq %rbp
movq %rsp, %rbp
movl $0x78, %eax
popq %rbp
retq
movdqa %xmm0, %xmm1
movhlps %xmm1, %xmm1
pshufd $0x31, %xmm0, %xmm2
pmuludq %xmm1, %xmm0
pshufd $0x31, %xmm1, %xmm1
pmuludq %xmm2, %xmm1
shufps $-0x78, %xmm1, %xmm0
pshufd $-0x28, %xmm0, %xmm0
pshufd $0x1, %xmm0, %xmm1
pshufd $0x31, %xmm0, %xmm2
pmuludq %xmm0, %xmm2
pmuludq %xmm0, %xmm1
shufps $-0x78, %xmm2, %xmm1
pshufd $-0x28, %xmm1, %xmm0
movd %xmm0, %eax
cmpl %edx, %r8d
je 0x100000f5d
nopw %cs:(%rax,%rax)
imull %edi, %eax
leal -0x1(%rdi), %ecx
cmpl $0x1, %ecx
movl %ecx, %edi
ja 0x100000f50
popq %rbp
retq
nop
pushq %rbp
movq %rsp, %rbp
movl $0x78, %eax
popq %rbp
retq
en pratique (clang)…
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
pushq %rbp
movq %rsp, %rbp
movl $0x78, %eax
popq %rbp
retq
pushq %rbp
movq %rsp, %rbp
movl $0x1, %eax
cmpl $0x2, %edi
jb 0x100000f5d
leal -0x1(%rdi), %r8d
movl %r8d, %ecx
en pratique (clang)…
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
Évaluation à l’exécution Évaluation à la compilation
en pratique (clang)…
static_assert
134
#include <type_traits>
template <typename T>
constexpr bool
is_power_of_two(T x)
{
static_assert( std::is_integral<T>::value
and std::is_unsigned<T>::value
, "Integral and unsigned type expected");
return x and ((x & (x-1)) == 0);
}
int main()
{
is_power_of_two(-2);
}
faire échouer la compilation sur un message clair
error: static_assert failed "Integral and unsigned type expected"
  static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value
  ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_assert
134
#include <type_traits>
template <typename T>
constexpr bool
is_power_of_two(T x)
{
static_assert( std::is_integral<T>::value
and std::is_unsigned<T>::value
, "Integral and unsigned type expected");
return x and ((x & (x-1)) == 0);
}
int main()
{
is_power_of_two(-2);
}
faire échouer la compilation sur un message clair
error: static_assert failed "Integral and unsigned type expected"
  static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value
  ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
expression constante requise
TEMPLATES
Généricité
136
struct foo_vector
{
foo* data;
unsigned int sz;
void push_back(const foo& x)
{
data[sz++] = x;
}
};
une nécessité pour les structures de données…
auto int_vec = int_vector{};
auto foo_vec = foo_vector{};
int_vec.push_back(1);
foo_vec.push_back(foo{});
struct int_vector
{
int* data;
unsigned int sz;
void push_back(const int& x)
{
data[sz++] = x;
}
};
Généricité
137
struct int_vector
{
int* data;
unsigned int sz;
void push_back(const int& x)
{
data[sz++] = x;
}
};
une nécessité pour les structures de données…
struct foo_vector
{
foo* data;
unsigned int sz;
void push_back(const foo& x)
{
data[sz++] = x;
}
};
Généricité
138
template <typename T>
struct vector
{
T* data;
unsigned int sz;
void push_back(const T& x)
{
data[sz++] = x;
}
};
une nécessité pour les structures de données…
auto int_vec = vector<int>{};
auto foo_vec = vector<foo>{};
int_vec.push_back(1);
foo_vec.push_back(foo{});
Généricité
138
template <typename T>
struct vector
{
T* data;
unsigned int sz;
void push_back(const T& x)
{
data[sz++] = x;
}
};
une nécessité pour les structures de données…
auto int_vec = vector<int>{};
auto foo_vec = vector<foo>{};
int_vec.push_back(1);
foo_vec.push_back(foo{});
“instanciation” du
type générique
vector
avec un entier
Généricité
139
int sum(const std::vector<int>& vec)
{
auto acc = int{};
for (const auto& x : vec)
acc = acc + x;
return acc;
}
une nécessité pour les algorithmes…
const auto vec0 = std::vector<int>{1,2,3};
const auto s0 = sum(vec0);
const auto vec1 = std::vector<foo>{1,2,3};
const auto s1 = sum(vec1);
struct foo;
foo operator+(const foo&, const foo&);
foo sum(const std::vector<foo>& vec)
{
auto acc = foo{};
for (const auto& x : vec)
acc = acc + x;
return acc;
}
Généricité
140
int sum(const std::vector<int>& vec)
{
auto acc = int{};
for (const auto& x : vec)
acc = acc + x;
return acc;
}
une nécessité pour les algorithmes…
foo sum(const std::vector<foo>& vec)
{
auto acc = foo{};
for (const auto& x : vec)
acc = acc + x;
return acc;
}
Généricité
141
template <typename T>
T sum(const std::vector<T>& vec)
{
auto acc = T{};
for (const auto& x : vec)
{
acc = acc + x;
}
return acc;
}
une nécessité pour les algorithmes…
const auto vec0 = std::vector<int>{1,2,3};
const auto s0 = sum(vec0);
const auto vec1 = std::vector<foo>{1,2,3};
const auto s1 = sum(vec1);
Généricité
141
template <typename T>
T sum(const std::vector<T>& vec)
{
auto acc = T{};
for (const auto& x : vec)
{
acc = acc + x;
}
return acc;
}
rien n’a
changé!
une nécessité pour les algorithmes…
const auto vec0 = std::vector<int>{1,2,3};
const auto s0 = sum(vec0);
const auto vec1 = std::vector<foo>{1,2,3};
const auto s1 = sum(vec1);
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_;}
T& x() {return x_;}
};
auto f_int = foo<int>{42};
f_int.x() += 2;
auto f_char = foo<char>{'a'};
f_char.x() = 'b';
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_;}
T& x() {return x_;}
};
paramètre générique : c’est
un type, pas une valeur
auto f_int = foo<int>{42};
f_int.x() += 2;
auto f_char = foo<char>{'a'};
f_char.x() = 'b';
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_;}
T& x() {return x_;}
};
paramètre générique : c’est
un type, pas une valeur
accès au type dans toute la classe
auto f_int = foo<int>{42};
f_int.x() += 2;
auto f_char = foo<char>{'a'};
f_char.x() = 'b';
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename T, typename U>
void fun1(const T&);
fun0(0, foo{});
fun1<int, foo>(0);
déduction automatique à partir des arguments
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename T, typename U>
void fun1(const T&);
fun0(0, foo{});
fun1<int, foo>(0);
déduction automatique à partir des arguments
tous les types sont
présents dans les
arguments
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename T, typename U>
void fun1(const T&);
fun0(0, foo{});
fun1<int, foo>(0);
déduction automatique à partir des arguments
tous les types sont
présents dans les
arguments
les types ne sont pas tous présents
dans les arguments, il donc les expliciter
Fonctions templates
144
template <typename T>
struct foo
{
T x;
};
template <typename T>
foo<T> mk_foo(const T& x)
{
return {x};
}
const auto f0 = foo<int>(42);
const auto f1 = mk_foo(42);
pratique pour “cacher” l’argument du template
Fonctions templates
144
template <typename T>
struct foo
{
T x;
};
template <typename T>
foo<T> mk_foo(const T& x)
{
return {x};
}
const auto f0 = foo<int>(42);
const auto f1 = mk_foo(42);
pratique pour “cacher” l’argument du template
pas de type explicite
Fonctions templates
145
les fonctions membres peuvent être aussi génériques
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
template <typename U>
void bar(const U&) {}
};
auto f = foo<int>{42};
f.bar(3.22);
Fonctions templates
145
les fonctions membres peuvent être aussi génériques
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
template <typename U>
void bar(const U&) {}
};
auto f = foo<int>{42};
f.bar(3.22);méthode générique
Templates :“fabriques”
146
• Une structure template est une “fabrique de type”
‣ template <typename T> struct foo n’est pas un type
- on ne peut pas créer d’objet de type foo<T>
‣ foo<int> est “généré” à partir de foo<T>
- c’est un type, on peut créer un objet à partir de foo<int>
• Une fonction template est une “fabrique de fonctions”
‣ on n’appelle pas directement template <typename T> foo()
Accès à un type imbriqué
147
struct bar
{
typedef int value_type;
};
void foo(const bar&)
{
bar::value_type x;
}
dans un contexte non-générique
Accès à un type imbriqué
147
struct bar
{
typedef int value_type;
};
void foo(const bar&)
{
bar::value_type x;
}
dans un contexte non-générique
OK
Accès à un type imbriqué
148
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
T::value_type x;
}
error: missing 'typename' prior to dependent type name 'T::value_type'
  T::value_type x;
  ^~~~~~~~~~~~~
  typename
dans un contexte générique
Accès à un type imbriqué
148
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
T::value_type x;
}
error: missing 'typename' prior to dependent type name 'T::value_type'
  T::value_type x;
  ^~~~~~~~~~~~~
  typename
!
dans un contexte générique
Accès à un type imbriqué
149
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
typename T::value_type x;
}
dans un contexte générique
Accès à un type imbriqué
149
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
typename T::value_type x;
}
dans un contexte générique
OK
150
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
{
const auto x = b.get<int>();
}
auto b = bar{};
foo(b);
error: use 'template' keyword to treat 'get' as a dependent template name
  const auto x = b.get<T>();
                   ^
                   template
150
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
{
const auto x = b.get<int>();
}
auto b = bar{};
foo(b);
error: use 'template' keyword to treat 'get' as a dependent template name
  const auto x = b.get<T>();
                   ^
                   template
!
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
{
const auto x = b.template get<int>();
}
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
{
const auto x = b.template get<int>();
}
OK
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
{
const auto x = b.template get<int>();
}
OK
get est une fonction template qui
dépend du type T qui est lui
même un paramètre template
alias
152
// the old way
typedef int my_typedef;
// aliases
using my_alias = int;
using : successeur de typedef
alias
152
// the old way
typedef int my_typedef;
// aliases
using my_alias = int;
lecture homogène avec auto var = …;
using : successeur de typedef
alias
153
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, int> type;
};
int main()
{
const auto f = templated_typedef<int>::type{};
}
essayons tout de même (1)
impossible d’avoir des typedef template
alias
154
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, int> type;
};
template <typename T>
void bar(const typename templated_typedef<T>::type&);
int main()
{
const auto f = templated_typedef<int>::type{};
bar(f);
}
impossible d’avoir des typedef template
essayons tout de même (2)
alias
154
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, int> type;
};
template <typename T>
void bar(const typename templated_typedef<T>::type&);
int main()
{
const auto f = templated_typedef<int>::type{};
bar(f);
}
note: candidate template ignored: couldn't infer template argument 'T'
void bar(const typename templated_typedef<T>::type&);
impossible d’avoir des typedef template
essayons tout de même (2)
!
alias
155
template <typename T, typename U>
struct foo{};
template <typename T>
using alias_t = foo<T, int>;
int main()
{
const auto f0 = foo<double, int>{};
const auto f1 = alias_t<int>{};
}
alias templates
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
deux types à déduire
template <typename T>
void f(const T& param);
int x = 42;
f(x);
pseudo-code :
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
template <typename T>
void f(const T& param);
int x = 42;
f(x);
pseudo-code :
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type de param
template <typename T>
void f(const T& param);
int x = 42;
f(x);
pseudo-code :
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type de param
template <typename T>
void f(const T& param);
int x = 42;
f(x);
int
pseudo-code :
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type de param
template <typename T>
void f(const T& param);
int x = 42;
f(x);
int
const int&
pseudo-code :
Règles de déductions
• Trois cas, le type de param
‣ est un pointeur ou une référence
‣ n’est ni un pointeur ni une référence
‣ est une référence universelle
157
template <typename T>
void f(ParamType param);
Règles de déductions
158
ParamType : pointeur ou référence (1)
template <typename T>
void f(T& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int int&
f(cx) const int const int&
f(rx) const int const int&
Règles de déductions
158
ParamType : pointeur ou référence (1)
template <typename T>
void f(T& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int int&
f(cx) const int const int&
f(rx) const int const int&
idem
pour les pointeurs
Règles de déductions
159
ParamType : pointeur ou référence (2)
template <typename T>
void f(const T& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int const int&
f(cx) const int const int&
f(rx) const int const int&
Règles de déductions
159
ParamType : pointeur ou référence (2)
template <typename T>
void f(const T& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int const int&
f(cx) const int const int&
f(rx) const int const int&
idem
pour les pointeurs
Règles de déductions
160
ParamType : ni pointeur, ni référence
template <typename T>
void f(T param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int int
f(cx) int int
f(rx) int int
Règles de déductions
160
ParamType : ni pointeur, ni référence
template <typename T>
void f(T param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int int
f(cx) int int
f(rx) int int
par valeur
Règles de déductions
160
ParamType : ni pointeur, ni référence
template <typename T>
void f(T param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int int
f(cx) int int
f(rx) int int
par valeur
copie :
const est ignoré
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int& int&
f(cx) const int& const int&
f(rx) const int& const int&
f(42) int int&&
lvalues
rvalues
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int& int&
f(cx) const int& const int&
f(rx) const int& const int&
f(42) int int&&
idem
pour les pointeurs
lvalues
rvalues
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x;
const int& rx = x;
T param
f(x) int& int&
f(cx) const int& const int&
f(rx) const int& const int&
f(42) int int&&
idem
pour les pointeurs
lvalues
rvalues
“référence universelle”
162
template <typename T>
void print_type()
{
std::cout << __PRETTY_FUNCTION__;
}
Afficher le type déduit
void print_type() [T = foo]
(GCC, clang)
163
template <typename T>
void print_type()
{
std::cout << __FUNCSIG__;
}
void _cdecl print_type<struct foo>(void)
(Visual Studio 2013)
Afficher le type déduit
164
template <typename T>
struct print_type;
print_type<foo>{};
(tous compilateurs)
Afficher le type déduit
error: implicit instantiation of undefined template 'print_type<foo>'
  print_type<foo>{};
  ^
164
template <typename T>
struct print_type;
print_type<foo>{};
(tous compilateurs)
Afficher le type déduit
ne pas donner de
définition
error: implicit instantiation of undefined template 'print_type<foo>'
  print_type<foo>{};
  ^
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T>
struct algo
{
void operator()()
{std::cout << "O(n)";}
};
template <>
struct algo<foo>
{
void operator()()
{std::cout << "O(1)";}
};
algo<foo>{}(); // “O(1)”
algo<int>{}(); // “O(n)”
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T>
struct algo
{
void operator()()
{std::cout << "O(n)";}
};
template <>
struct algo<foo>
{
void operator()()
{std::cout << "O(1)";}
};
algo<foo>{}(); // “O(1)”
algo<int>{}(); // “O(n)”
générique
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T>
struct algo
{
void operator()()
{std::cout << "O(n)";}
};
template <>
struct algo<foo>
{
void operator()()
{std::cout << "O(1)";}
};
algo<foo>{}(); // “O(1)”
algo<int>{}(); // “O(n)”
spécialisation
générique
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
algo(foo{}); // “O(1)”
algo(42); // “O(n)”
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
algo(foo{}); // “O(1)”
algo(42); // “O(n)”
générique
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
algo(foo{}); // “O(1)”
algo(42); // “O(n)”
spécialisation
générique
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
void algo(const foo&)
{
std::cout << "O(1) bis";
}
algo(foo{}); // “O(1) bis”
algo(42); // “O(n)”
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
void algo(const foo&)
{
std::cout << "O(1) bis";
}
algo(foo{}); // “O(1) bis”
algo(42); // “O(n)”
spécialisation
générique
surcharge
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
void algo(const foo&)
{
std::cout << "O(1)";
}
void algo(const foo&)
{
std::cout << "O(1) bis";
}
algo(foo{}); // “O(1) bis”
algo(42); // “O(n)”
spécialisation
générique
surcharge
préférer les surcharges
aux spécialisations
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
générique
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
générique
spécialisation
partielle
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
template <>
struct algo<std::vector<double>>
{
void operator()() {std::cout << "O(1) double";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
algo<std::vector<double>>{}(); // “O(1) double”
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
template <>
struct algo<std::vector<double>>
{
void operator()() {std::cout << "O(1) double";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
algo<std::vector<double>>{}(); // “O(1) double”
générique
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
template <>
struct algo<std::vector<double>>
{
void operator()() {std::cout << "O(1) double";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
algo<std::vector<double>>{}(); // “O(1) double”
générique
spécialisation
partielle
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator()() {std::cout << "O(n)";}
};
template <typename T>
struct algo<std::vector<T>>
{
void operator()() {std::cout << "O(1)";}
};
template <>
struct algo<std::vector<double>>
{
void operator()() {std::cout << "O(1) double";}
};
algo<int>{}(); // “O(n)”
algo<std::vector<int>>{}(); // “O(1)”
algo<std::vector<double>>{}(); // “O(1) double”
générique
spécialisation
partielle
spécialisation
totale
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, vector>{};
prendre en paramètre template un template (1)
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, vector>{};
obligatoire
prendre en paramètre template un template (1)
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, vector>{};
obligatoire
nom sans importance
peut être omis
prendre en paramètre template un template (1)
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, vector>{};
obligatoire
nom sans importance
peut être omis
T est passé à Container
prendre en paramètre template un template (1)
Template-template arguments
171
template <typename T, template <typename> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, std::vector>{};
prendre en paramètre template un template (2)
error: template template argument has different template parameters than its
corresponding template template parameter
  foo<int, std::vector>{};
                ^
note: too many template parameters in template template argument
template <class _Tp, class _Allocator = allocator<_Tp> >
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
attention aux nombres de paramètres…
Template-template arguments
171
template <typename T, template <typename> class Container>
struct foo
{
Container<T> cont_;
};
foo<int, std::vector>{};
prendre en paramètre template un template (2)
!
error: template template argument has different template parameters than its
corresponding template template parameter
  foo<int, std::vector>{};
                ^
note: too many template parameters in template template argument
template <class _Tp, class _Allocator = allocator<_Tp> >
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
attention aux nombres de paramètres…
Valeurs en paramètres template
172
template <int Value>
struct foo
{
void operator()() const
{
std::cout << Value;
}
};
foo<42>{}();
on peut utiliser des valeurs comme paramètres template
template <bool Value>
struct foo
{
void operator()() const
{
std::cout << Value;
}
};
foo<true>{}();
Valeurs en paramètres template
173
expressions constantes seulement
template <int Value>
struct foo;
const auto i = 42;
auto j = i;
foo<i>{}(); // OK
foo<j>{}(); // ERROR
error: non-type template argument is not a constant expression
  foo<j>{}(); // ERROR
      ^
note: read of non-const variable 'j' is not allowed in a constant expression
Valeurs en paramètres template
173
expressions constantes seulement
template <int Value>
struct foo;
const auto i = 42;
auto j = i;
foo<i>{}(); // OK
foo<j>{}(); // ERROR
!
error: non-type template argument is not a constant expression
  foo<j>{}(); // ERROR
      ^
note: read of non-const variable 'j' is not allowed in a constant expression
Valeurs en paramètres template
174
la spécialisation fonctionne aussi
template <int Value>
struct fact
{
static const auto value = Value * fact<Value - 1>::value;
};
template <>
struct fact<0>
{
static const auto value = 1;
};
std::cout << fact<5>::value; // 120
Valeurs en paramètres template
174
la spécialisation fonctionne aussi
template <int Value>
struct fact
{
static const auto value = Value * fact<Value - 1>::value;
};
template <>
struct fact<0>
{
static const auto value = 1;
};
std::cout << fact<5>::value; // 120
récursion : cas général
récursion : cas de base
Curiously RecurringTemplate Pattern (CRTP)
175
template <typename T>
struct foo
{};
struct bar
: public foo<bar>
{};
classe héritée générique
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
add(1,2); // 3
add(1,2,3); // 6
add(1,2,3,4); // 10
// etc.
nombre variable de paramètres template
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
add(1,2); // 3
add(1,2,3); // 6
add(1,2,3,4); // 10
// etc.
nombre variable de paramètres template
“parameter pack”
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
add(1,2); // 3
add(1,2,3); // 6
add(1,2,3,4); // 10
// etc.
nombre variable de paramètres template
expansion du pack
“parameter pack”
Variadic templates
177
int add(int arg1)
{
return arg1;
}
int add(int arg1, int arg2)
{
return arg1 + add(arg2);
}
int add(int arg1, int arg2, int arg3)
{
return arg1 + add(arg2, arg3);
}
add(1,2,3); // 6
code “déroulé”
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
“déconstruction" de la liste de types head::tail
Caml, Standard ML, Haskell, Scala, etc.
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
head
“déconstruction" de la liste de types head::tail
Caml, Standard ML, Haskell, Scala, etc.
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
head tail
“déconstruction" de la liste de types head::tail
Caml, Standard ML, Haskell, Scala, etc.
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
template<typename T, typename... Ts>
T add(T x, Ts... xs)
{
return x + add(xs...);
}
head tail
“déconstruction" de la liste de types head::tail
Caml, Standard ML, Haskell, Scala, etc.
head
Variadic templates
179
template<typename T>
T add(T v)
{
return v;
}
template<typename T, typename... Args>
T add(T first, Args... args)
{
return first + add(args...);
}
std::string operator ""_s(const char *str, std::size_t)
{
return {str};
}
add(“1”_s,"2"_s,"3"_s); // “123”
pour le plaisir…
Variadic templates
180
// Signature of a meta-function that add integers
template <int... Xs>
struct add;
template <int X, int... Xs>
struct add<X, Xs...>
{
static const auto value = X + add<Xs...>::value;
};
template <int X>
struct add<X>
{
static const auto value = X ;
};
add<1,2,3>::value; // 6
les struct/class aussi
Variadic templates
181
connaître la taille d’un pack avec sizeof...
template <typename... Ts>
std::size_t foo()
{
return sizeof...(Ts);
}
std::cout << foo<int, double, char>(); // 3
Variadic templates
182
expansion d’un pack (1)
template <typename... Ts>
struct foo{};
template<typename X, typename Y, typename... Z>
void
bar(X, Y, Z...)
{
print_type< foo<X, Y, Z...> >();
print_type< foo<X, Z..., Y> >();
print_type< foo<Z..., X, Y> >();
}
bar(int{}, int{}, double{}, std::string{});
void print_type() [T = foo<int, int, double, std::__1::basic_string<char> >]
void print_type() [T = foo<int, double, std::__1::basic_string<char>, int>]
void print_type() [T = foo<double, std::__1::basic_string<char>, int, int>]
Variadic templates
182
expansion d’un pack (1)
template <typename... Ts>
struct foo{};
template<typename X, typename Y, typename... Z>
void
bar(X, Y, Z...)
{
print_type< foo<X, Y, Z...> >();
print_type< foo<X, Z..., Y> >();
print_type< foo<Z..., X, Y> >();
}
bar(int{}, int{}, double{}, std::string{});
void print_type() [T = foo<int, int, double, std::__1::basic_string<char> >]
void print_type() [T = foo<int, double, std::__1::basic_string<char>, int>]
void print_type() [T = foo<double, std::__1::basic_string<char>, int, int>]
Z… en dernière position
Variadic templates
183
expansion d’un pack (2)
template<typename... Values>
std::array<int, sizeof...(Values)>
make_array(Values... values)
{
return std::array<int, sizeof...(Values)>{values...};
}
const auto a = make_array(1,2,3);
template<typename... Args>
void
foo(Args... values)
{
int tab[sizeof...(Args)] = {values...};
}
foo(1,2,3);
Variadic templates
184
expansion d’un pack : héritage
struct base1
{
void foo(){}
};
struct base2
{
void bar(){}
};
template <typename... Bases>
class derived
: public Bases...
{};
auto d = derived<base1, base2>{};
d.foo();
d.bar();
Variadic templates
185
spécialisation
template <typename... Ts>
struct foo
{};
template <typename... Ts>
struct bar;
template <typename... Ts>
struct bar<foo<Ts...>>
{};
using foo_type = foo<int, char>;
using bar_type = bar<foo_type>;
Variadic templates
185
spécialisation
template <typename... Ts>
struct foo
{};
template <typename... Ts>
struct bar;
template <typename... Ts>
struct bar<foo<Ts...>>
{};
using foo_type = foo<int, char>;
using bar_type = bar<foo_type>;
permet d’accéder
à liste de
paramètres de foo
Variadic templates
186
template <typename... Ts>
struct tuple {};
template <typename T, typename... Ts>
struct tuple<T, Ts...>
: tuple<Ts...>
{
tuple(T t, Ts... ts)
: tuple<Ts...>(ts...)
, current(t)
{}
T current;
};
structure récursive
Références universelles
187
template <typename T>
void f(T&& param);
• Dénomination de Scott Meyers
• En présence d’une déduction de type (templates)
• Il faudrait parler de
‣ forwarding reference
‣ en cours de standardisation (la dénomination)
‣ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/
n4164.pdf
Références universelles
187
template <typename T>
void f(T&& param);
• Dénomination de Scott Meyers
• En présence d’une déduction de type (templates)
• Il faudrait parler de
‣ forwarding reference
‣ en cours de standardisation (la dénomination)
‣ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/
n4164.pdf
&& sur paramètre template
Perfect forwarding
188
le problème : passer des paramètres
de manière transparente à une sous-fonction
template <typename Fun, typename T>
void logger(const T& x)
{
std::cout << "beforen";
Fun{}(x);
std::cout << "aftern";
}
template <typename Fun, typename T>
void logger(T& x)
{
std::cout << "beforen";
Fun{}(x);
std::cout << "aftern";
}
et s’il y a plusieurs paramètres?…
Perfect forwarding
solution : std::forward
template <typename Fun, typename Arg>
void logger(Arg&& x)
{
std::cout << "beforen";
Fun{}(std::forward<Arg>(x));
std::cout << "aftern";
}
Perfect forwarding
190
comment ça fonctionne? (1)
A& & → A&
A& && → A&
A&& & → A&
A&& && → A&&
si invocation f(a)
a de type A Arg x
lvalue A& A&
rvalue A&& A&&
template<typename Arg>
void f(Arg&& x);
“collapsing rules”
application des collapsing rules
Perfect forwarding
191
comment ça fonctionne? (2)
template<class T>
T&&
forward(typename remove_reference<T>::type& a)
{
return static_cast<T&&>(a);
}
Perfect forwarding
192
void logger(X& && x)
{
std::cout << "beforen";
Fun{}(std::forward<X&>(x));
std::cout << "aftern";
}
X& &&
forward(typename remove_reference<X&>::type& a)
{
return static_cast<X& &&>(a);
}
void logger(X& x)
{
std::cout << "beforen";
Fun{}(std::forward<X&>(x));
std::cout << "aftern";
}
X&
forward(X& a)
{
return static_cast<X&>(a);
}
sur une lvalue
Perfect forwarding
193
sur une rvalue
void logger(X&& && x)
{
std::cout << "beforen";
Fun{}(std::forward<X&&>(x));
std::cout << "aftern";
}
X&& &&
forward(typename remove_reference<X&&>::type& a)
{
return static_cast<X&& &&>(a);
}
void logger(X&& x)
{
std::cout << "beforen";
Fun{}(std::forward<X&&>(x));
std::cout << "aftern";
}
X&&
forward(X& a)
{
return static_cast<X&&>(a);
}
Perfect forwarding vs move
194
void foo(int&&) {std::cout << "int&&";}
void foo(const int&) {std::cout << "const int&";}
void foo(int&) {std::cout << "int&";}
template <typename T>
void apply(T&& x)
{
std::cout << "A";
foo(std::forward<T>(x));}
}
void apply(int&& x)
{
std::cout << "B";
foo(std::move(x));
}
apply(i);
apply(ri);
apply(cri);
apply(42);
apply(std::move(i));
quel est l’affichage?
auto i = 2;
auto& ri = i;
const auto& cri = i;
BIBLIOTHÈQUE STANDARD
196
begin/end
auto vec = std::vector<int>{1,2,3};
auto it = begin(vec); // vec.begin()
*it = 42;
auto cit = cbegin(vec); // vec.cbegin()
*cit = 33; // error
fonctions libres
for (auto cit = cbegin(vec); cit != cend(vec); ++cit)
{
// ...
}
197
begin/end
tableaux C
int tab[] = {1,2,3};
for (auto it = std::begin(tab); it != std::end(tab); ++it)
{
*it = 0;
}
197
begin/end
tableaux C
int tab[] = {1,2,3};
for (auto it = std::begin(tab); it != std::end(tab); ++it)
{
*it = 0;
}
appel “fully qualified”
198
next/prev
auto vec = std::vector<int>{1,2,3};
auto it = begin(vec);
auto it1 = next(it); // return a copy incremented by 1
auto it2 = next(it, 2); // return a copy incremented by 2
auto it3 = prev(it2); // return a copy decremented by 1
auto it4 = prev(it3, 1); // return a copy decremented by 1
199
move
déplacer un conteneur
auto vec1 = std::vector<foo>{foo{}, foo{}};
auto vec2 = std::vector<foo>{};
std::cout << vec1.size();
std::cout << vec2.size();
std::move(begin(vec1), end(vec1), std::back_inserter(vec2));
std::cout << vec1.size();
std::cout << vec2.size();
200
all_of, any_of, any_of
auto vec1 = std::vector<bool>{true, true, true};
auto vec2 = std::vector<bool>{true, false, true};
std::cout << std::boolalpha;
std::cout << std::all_of( begin(vec1), end(vec1)
, [](bool x){return x;});
std::cout << std::any_of( begin(vec2), end(vec2)
, [](bool x){return not x;});
201
emplace, emplace_back
construction en place grâce au perfect forwarding
struct foo
{
foo(int)
{std::cout << "foo(int)";}
foo(const foo&)
{std::cout << "foo(const foo&)";}
foo& operator=(const foo&)
{std::cout << "operator=(const foo&)"; return *this;}
foo(foo&&)
{std::cout << "foo(foo&&)";}
foo& operator=(foo&&)
{std::cout << "operator=(foo&&)"; return *this;}
};
auto vec1 = std::vector<foo>{};
vec1.reserve(3);
auto f = foo{1};
vec1.push_back(f);
vec1.push_back(foo{2});
vec1.emplace_back(3);
202
shrink_to_fit
deque, string et vector
auto vec1 = std::vector<int>{};
std::cout << vec1.capacity();
vec1.push_back(1);
vec1.push_back(1);
vec1.push_back(1);
std::cout << vec1.capacity();
vec1.shrink_to_fit();
std::cout << vec1.capacity();
peut libérer de la mémoire
203
forward_list
liste simplement chaînée
auto l = std::forward_list<int>{1,2,3};
std::cout << l.size(); // error, no size() member
auto cit0 = begin(l);
auto cit1 = next(cit0);
auto cit2 = prev(cit1); // error, not bidirectional
204
array
auto a1 = std::array<int, 3>{};
const auto cit = a1.cbegin();
const auto& x = a1[2]; // use like a C-array
const auto& y = a1.at(10); // std::out_of_range
auto a2 = std::array<int, 3>{};
if (a1 == a2)
{
// ...
}
auto a3 = a1;
// etc.
tableaux C pour le C++
strictement les mêmes performances!
à privilégier dans tout nouveau code
205
array
const auto a0 = std::array<int, 3>{1,2,3};
const auto a1 = a0;
toutes les facilités du C++ (1)
const int t0[3] = {1,2,3};
int t1[3];
std::copy(t0, t0 + 3, t1);
vs
copie
205
array
const auto a0 = std::array<int, 3>{1,2,3};
const auto a1 = a0;
toutes les facilités du C++ (1)
dangereux
const int t0[3] = {1,2,3};
int t1[3];
std::copy(t0, t0 + 3, t1);
vs
copie
206
array
const auto a0 = std::array<int, 3>{1,2,3};
const auto res = std::find(begin(a0), end(a0), 3);
if (res != end(a0))
{
std::cout << "foundn";
}
toutes les facilités du C++ (2)
utilisation des algorithmes STL
207
array
auto a0 = std::array<int, 3>{1, 2, 3};
auto a1 = std::array<int, 3>{1, 99, 3};
const auto res = memcmp(a0.data(), a1.data(), 3 * sizeof(int));
std::cout << res << 'n';
memcpy(a0.data(), a1.data(), 3 * sizeof(int));
for (auto x : a0)
{
std::cout << x << 'n';
}
utilisation avec les fonctions C
.data() pour accéder au tableau C
208
tuple
conteneur de types hétérogène
auto t1 = std::tuple<int, char, foo>{2, 'a', foo{}};
auto t2 = std::make_tuple(2, 'a', foo{});
const auto& f = std::get<2>(t2);
209
tuple
permet de retourner plusieurs valeurs
sans avoir à créer un nouveau type (1)
struct foo {};
std::tuple<int, foo>
bar()
{
return std::make_tuple(2, foo{});
}
const auto t = bar();
210
tuple
permet de retourner plusieurs valeurs
sans avoir à créer un nouveau type (2)
struct foo {};
std::tuple<int, foo>
bar()
{
return std::make_tuple(2, foo{});
}
auto i = 0;
auto f = foo{};
std::tie(i, f) = bar();
std::cout << i; // 2
211
tuple
concaténer des tuples
auto t0 = std::make_tuple(1, foo{}, 'a');
std::cout << std::tuple_size<decltype(t0)>::value; // 3
auto t1 = std::make_tuple(3.14, std::string{"abc"});
std::cout << std::tuple_size<decltype(t1)>::value; // 2
auto t2 = std::tuple_cat(t0, t1);
std::cout << std::tuple_size<decltype(t2)>::value; // 5
212
unordered_map
table de hachage
auto map = std::unordered_map<int, std::string>{};
map.insert({42, "abc"});
map.emplace(33, "def");
for (const auto& key_value : map)
{
std::cout << key_value.first << " -> " << key_value.second;
}
fonctionne comme std::map
213
unordered_map
fonctions spécifiques aux tables de hachage
auto map = std::unordered_map<int, std::string>{1'000'000};
peut-être initialisée avec un nombre de buckets
map.rehash(2'000'000);
peut-être redimensionnée
map.load_factor()
afficher le facteur de charge
214
unordered_map
utiliser un type personnalisé en tant que clé
namespace std
{
template <>
struct hash<foo>
{
std::size_t
operator()(const foo& f)
const
{
// hash function
}
};
}
bool operator==(const foo&, const foo&);
struct foo
{
// some data
};
clé
égalité
hachage
214
unordered_map
utiliser un type personnalisé en tant que clé
namespace std
{
template <>
struct hash<foo>
{
std::size_t
operator()(const foo& f)
const
{
// hash function
}
};
}
bool operator==(const foo&, const foo&);
struct foo
{
// some data
};
clé
égalité
hachage
spécialisation
215
unordered_map
bonus: combiner des valeurs de hachage (1)
/// @brief Combine the hash value of x with seed.
///
/// Taken from <boost/functional/hash.hpp>.
/// Sligthy modified to use std::hash<T> instead of
/// boost::hash_value().
template <typename T>
inline
void
hash_combine(std::size_t& seed, const T& x)
noexcept(noexcept(std::hash<T>()(x)))
{
seed ^= std::hash<T>()(x) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
216
unordered_map
bonus: combiner des valeurs de hachage (2)
namespace std
{
template <>
struct hash<foo>
{
std::size_t
operator()(const foo& f)
const
{
auto seed = 0ul;
hash_combine(seed, f.x);
hash_combine(seed, f.y);
return seed;
}
};
}
217
Gestion de la mémoire
• introduction de unique_ptr
‣ auto_ptr deprecated
‣ utilise les portées pour désallouer
• introduction de shared_ptr
‣ déjà présent dans Boost et POCCO
‣ comptage de référence
• désallocation automatique dans tous les cas
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14
C++ 11/14

Mais conteúdo relacionado

Mais procurados

C++11 en 12 exemples simples
C++11 en 12 exemples simplesC++11 en 12 exemples simples
C++11 en 12 exemples simplesPethrvs
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelleMICHRAFY MUSTAFA
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMALoic Yon
 
Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieurFredy Fadel
 
Développement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresDéveloppement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresECAM Brussels Engineering School
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryneuros
 
Les nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneLes nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneMicrosoft
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French CourseHaytam EL YOUSSFI
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelThierry Gayet
 
Chapitre6: Surcharge des opérateurs
Chapitre6:  Surcharge des opérateursChapitre6:  Surcharge des opérateurs
Chapitre6: Surcharge des opérateursAziz Darouichi
 
Python avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de donnéesPython avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de donnéesECAM Brussels Engineering School
 
Développement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbreDéveloppement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbreECAM Brussels Engineering School
 
Initiation à l'algorithmique
Initiation à l'algorithmiqueInitiation à l'algorithmique
Initiation à l'algorithmiqueAbdoulaye Dieng
 
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...MICHRAFY MUSTAFA
 
Programmation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulationProgrammation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulationECAM Brussels Engineering School
 
Mémento caml
Mémento camlMémento caml
Mémento camlzan
 
Chapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaChapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaAziz Darouichi
 
Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)Stéphanie Hertrich
 

Mais procurados (20)

C++11 en 12 exemples simples
C++11 en 12 exemples simplesC++11 en 12 exemples simples
C++11 en 12 exemples simples
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelle
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMA
 
Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieur
 
Développement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresDéveloppement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulières
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jquery
 
Python avancé : Qualité de code et convention de codage
Python avancé : Qualité de code et convention de codagePython avancé : Qualité de code et convention de codage
Python avancé : Qualité de code et convention de codage
 
Les nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ ModerneLes nouveautés de C++11 : Ecrire du C++ Moderne
Les nouveautés de C++11 : Ecrire du C++ Moderne
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French Course
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appel
 
Type abstrait de données
Type abstrait de donnéesType abstrait de données
Type abstrait de données
 
Chapitre6: Surcharge des opérateurs
Chapitre6:  Surcharge des opérateursChapitre6:  Surcharge des opérateurs
Chapitre6: Surcharge des opérateurs
 
Python avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de donnéesPython avancé : Ensemble, dictionnaire et base de données
Python avancé : Ensemble, dictionnaire et base de données
 
Développement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbreDéveloppement informatique : Algorithmique I : Récursion et arbre
Développement informatique : Algorithmique I : Récursion et arbre
 
Initiation à l'algorithmique
Initiation à l'algorithmiqueInitiation à l'algorithmique
Initiation à l'algorithmique
 
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
 
Programmation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulationProgrammation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulation
 
Mémento caml
Mémento camlMémento caml
Mémento caml
 
Chapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En JavaChapitre8: Collections et Enumerations En Java
Chapitre8: Collections et Enumerations En Java
 
Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)
 

Destaque

Report on GPU complex type usage
Report on GPU complex type usageReport on GPU complex type usage
Report on GPU complex type usageCaner Candan
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++Deepak Tathe
 
Exception handling in c++ by manoj vasava
Exception handling in c++ by manoj vasavaException handling in c++ by manoj vasava
Exception handling in c++ by manoj vasavaManoj_vasava
 
4.0 projek pengaturcaraan
4.0 projek pengaturcaraan4.0 projek pengaturcaraan
4.0 projek pengaturcaraanSakinah Hassan
 
Principles and advantages of oop ppt
Principles and advantages of oop pptPrinciples and advantages of oop ppt
Principles and advantages of oop pptdaxesh chauhan
 
C++ vs C#
C++ vs C#C++ vs C#
C++ vs C#sudipv
 
Exception Handling
Exception HandlingException Handling
Exception HandlingReddhi Basu
 
Templates in C++
Templates in C++Templates in C++
Templates in C++Tech_MX
 
Oop c++class(final).ppt
Oop c++class(final).pptOop c++class(final).ppt
Oop c++class(final).pptAlok Kumar
 
Introduction à la metaprogrammation en C++
Introduction à la metaprogrammation en C++Introduction à la metaprogrammation en C++
Introduction à la metaprogrammation en C++galinierf
 
01 c++ Intro.ppt
01 c++ Intro.ppt01 c++ Intro.ppt
01 c++ Intro.pptTareq Hasan
 
CPR 11-12 PIALE Inglés (tarde)
CPR 11-12 PIALE Inglés (tarde)CPR 11-12 PIALE Inglés (tarde)
CPR 11-12 PIALE Inglés (tarde)Marga Gentil
 

Destaque (20)

openFrameworks
openFrameworksopenFrameworks
openFrameworks
 
Report on GPU complex type usage
Report on GPU complex type usageReport on GPU complex type usage
Report on GPU complex type usage
 
Introduction à C++
Introduction à C++Introduction à C++
Introduction à C++
 
Pengaturcaraan asas
Pengaturcaraan asasPengaturcaraan asas
Pengaturcaraan asas
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++
 
Exception handling in c++ by manoj vasava
Exception handling in c++ by manoj vasavaException handling in c++ by manoj vasava
Exception handling in c++ by manoj vasava
 
4.0 projek pengaturcaraan
4.0 projek pengaturcaraan4.0 projek pengaturcaraan
4.0 projek pengaturcaraan
 
Principles and advantages of oop ppt
Principles and advantages of oop pptPrinciples and advantages of oop ppt
Principles and advantages of oop ppt
 
C++ vs C#
C++ vs C#C++ vs C#
C++ vs C#
 
Exception Handling
Exception HandlingException Handling
Exception Handling
 
Ppt of c++ vs c#
Ppt of c++ vs c#Ppt of c++ vs c#
Ppt of c++ vs c#
 
Templates in C++
Templates in C++Templates in C++
Templates in C++
 
Oop c++class(final).ppt
Oop c++class(final).pptOop c++class(final).ppt
Oop c++class(final).ppt
 
Introduction à la metaprogrammation en C++
Introduction à la metaprogrammation en C++Introduction à la metaprogrammation en C++
Introduction à la metaprogrammation en C++
 
01 c++ Intro.ppt
01 c++ Intro.ppt01 c++ Intro.ppt
01 c++ Intro.ppt
 
Oops ppt
Oops pptOops ppt
Oops ppt
 
Convocatoria libro asomese
Convocatoria libro asomeseConvocatoria libro asomese
Convocatoria libro asomese
 
09140067
0914006709140067
09140067
 
CPR 11-12 PIALE Inglés (tarde)
CPR 11-12 PIALE Inglés (tarde)CPR 11-12 PIALE Inglés (tarde)
CPR 11-12 PIALE Inglés (tarde)
 
Bizarre
BizarreBizarre
Bizarre
 

Semelhante a C++ 11/14

Cours langage c
Cours langage cCours langage c
Cours langage ccoursuniv
 
Cours c#
Cours c#Cours c#
Cours c#zan
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScriptAbdoulaye Dieng
 
initiation au javascript
initiation au javascriptinitiation au javascript
initiation au javascriptAbdoulaye Dieng
 
02 Spécificité du C++ COURS SYS SYSSSSSS
02 Spécificité du C++  COURS SYS SYSSSSSS02 Spécificité du C++  COURS SYS SYSSSSSS
02 Spécificité du C++ COURS SYS SYSSSSSSAyoubElmrabet6
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScriptAbdoulaye Dieng
 
Chap 1 Initiation.pptx
Chap 1 Initiation.pptxChap 1 Initiation.pptx
Chap 1 Initiation.pptxolfaharrabi2
 
C1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieC1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieLoic Yon
 
Découvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDécouvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDotNetHub
 
.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHPAbdoulaye Dieng
 
Développer en natif avec C++11
Développer en natif avec C++11Développer en natif avec C++11
Développer en natif avec C++11Microsoft
 
Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Dr Samir A. ROUABHI
 
Boosted Java to Native Interface (JNI)
Boosted Java to Native Interface (JNI)Boosted Java to Native Interface (JNI)
Boosted Java to Native Interface (JNI)Innobec
 

Semelhante a C++ 11/14 (20)

Cours langage c
Cours langage cCours langage c
Cours langage c
 
Theme 6
Theme 6Theme 6
Theme 6
 
Theme 7
Theme 7Theme 7
Theme 7
 
Cours c#
Cours c#Cours c#
Cours c#
 
Le langage C
Le langage CLe langage C
Le langage C
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScript
 
initiation au javascript
initiation au javascriptinitiation au javascript
initiation au javascript
 
02 Spécificité du C++ COURS SYS SYSSSSSS
02 Spécificité du C++  COURS SYS SYSSSSSS02 Spécificité du C++  COURS SYS SYSSSSSS
02 Spécificité du C++ COURS SYS SYSSSSSS
 
C++11
C++11C++11
C++11
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScript
 
Chap 1 Initiation.pptx
Chap 1 Initiation.pptxChap 1 Initiation.pptx
Chap 1 Initiation.pptx
 
C1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieC1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partie
 
Formation python
Formation pythonFormation python
Formation python
 
Découvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCLDécouvrez C# 4.0 et les améliorations apportées à la BCL
Découvrez C# 4.0 et les améliorations apportées à la BCL
 
.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP
 
Développer en natif avec C++11
Développer en natif avec C++11Développer en natif avec C++11
Développer en natif avec C++11
 
Support programmation orientée objet c# .net version f8
Support programmation orientée objet c#  .net version f8Support programmation orientée objet c#  .net version f8
Support programmation orientée objet c# .net version f8
 
La première partie de la présentation PHP
La première partie de la présentation PHPLa première partie de la présentation PHP
La première partie de la présentation PHP
 
Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)
 
Boosted Java to Native Interface (JNI)
Boosted Java to Native Interface (JNI)Boosted Java to Native Interface (JNI)
Boosted Java to Native Interface (JNI)
 

C++ 11/14

  • 3. C++11/14 3 • Nouveau langage • Possiblement des gains de performance juste en recompilant • rvalues references, move semantics • Quelques incompatibilités avec le standard précédent, mais bien souvent pour plus de sécurité ou de performances • ex. un destructeur ne peut plus lever d’exception par défaut (ce qui était déjà une mauvaise chose) • ex. règles de conversion plus strictes dans l’initialisation d’agrégats int tab[] = {1.0}; // compilation error
  • 4. 4 ranged-base for loop auto constexpr static_assert rvalues references enum class uniform initialization noexcept variadic templates relaxed POD definition nullptr unrestricted unions lambdas decltype trailing return type extern template final override >> user-defined literals alignas alignof
  • 6. Compilateurs 6 • Visual Studio 2013 (incomplet) ‣ http://msdn.microsoft.com/en-us/library/hh567368.aspx ‣ plus gros manque : constexpr • Clang ≥ 3.3 ‣ http://clang.llvm.org/cxx_status.html • GCC ≥ 4.8 ‣ https://gcc.gnu.org/projects/cxx0x.html
  • 9. Boucles simplifiées 9 #include <iostream> #include <vector> int main() { std::vector<int> v; v.push_back(1); v.push_back(2); for ( std::vector<int>::const_iterator cit = v.begin() ; cit != v.end(); ++cit) { std::cout << *cit << ','; } } À l’ancienne : utilisation des itérateurs
  • 10. Boucles simplifiées 10 #include <iostream> #include <vector> int main() { std::vector<int> v; v.push_back(1); v.push_back(2); for (int i : v) { std::cout << i << ','; } } Syntaxe simplifiée
  • 11. Boucles simplifiées 10 #include <iostream> #include <vector> int main() { std::vector<int> v; v.push_back(1); v.push_back(2); for (int i : v) { std::cout << i << ','; } } Syntaxe simplifiée écriture naturelle
  • 12. Boucles simplifiées 11 { typedef std::vector<int>::const_iterator cit_t; for ( cit_t __begin = v.begin(), __end = v.end() ; __begin != __end; ++__begin) { int i = *__begin; std::cout << i << ','; } } sous le capot :
  • 13. Boucles simplifiées 12 std::map<int, int> m; m.insert(std::make_pair(1,1)); for (std::map<int, int>::value_type key_value : m) { std::cout << key_value.first << ',' << key_value.second; } n’importe quel conteneur fournissant des itérateurs
  • 14. Boucles simplifiées 12 std::map<int, int> m; m.insert(std::make_pair(1,1)); for (std::map<int, int>::value_type key_value : m) { std::cout << key_value.first << ',' << key_value.second; } n’importe quel conteneur fournissant des itérateurs pas de ‘&’ →copie
  • 15. Boucles simplifiées 13 const int tab[] = {1,2,3}; for (int x : tab) { std::cout << x << 'n'; } tableaux C
  • 16. Boucles simplifiées 14 • En résumé, fonctionne pour ‣ les tableaux C ‣ tous les types qui fournissent - les fonctions membres begin(), end() - les fonctions libres begin(type), end(type)
  • 17. auto 15 #include <map> int main() { std::map<int, int> m; m.insert(std::make_pair(1,1)); for (std::pair<int, int>& key_value : m) { // do something with key_value } } où est le problème?
  • 18. auto 16 #include <map> int main() { std::map<int, int> m; m.insert(std::make_pair(1,1)); for (std::pair<const int, int>& key_value : m) { // ... } } où est le problème?
  • 19. auto 16 #include <map> int main() { std::map<int, int> m; m.insert(std::make_pair(1,1)); for (std::pair<const int, int>& key_value : m) { // ... } } où est le problème? la clef dans une std::map est constante
  • 20. auto 17 #include <map> int main() { std::map<int, int> m; m.insert(std::make_pair(1,1)); for (auto& key_value : m) { // ... } }
  • 21. auto 17 #include <map> int main() { std::map<int, int> m; m.insert(std::make_pair(1,1)); for (auto& key_value : m) { // ... } } le compilateur fait le travail pour nous : plus d’erreur possible
  • 22. 18 auto #include <map> int main() { auto m = std::map<int, int>(); m.insert(std::make_pair(1,1)); for (auto& key_value : m) { // do something with key_value } }
  • 23. 18 auto #include <map> int main() { auto m = std::map<int, int>(); m.insert(std::make_pair(1,1)); for (auto& key_value : m) { // do something with key_value } } pour toute variable
  • 24. 19 auto m = std::map<int, int>(); for (const auto& key_value : m) { key_value.second = 2; // compilation error } auto auto utilise les règles de déduction des templates
  • 25. 20 #include <vector> std::vector<int> fun() { // return something } int main() { const auto container = fun(); for (const auto& value : container) { // do something } } auto facilite la maintenance de code
  • 26. 21 #include <deque> std::deque<int> fun() { // return something } int main() { const auto container = fun(); for (const auto& value : container) { // do something } } facilite la maintenance de code auto
  • 27. 21 #include <deque> std::deque<int> fun() { // return something } int main() { const auto container = fun(); for (const auto& value : container) { // do something } } fun() change facilite la maintenance de code auto
  • 28. 21 #include <deque> std::deque<int> fun() { // return something } int main() { const auto container = fun(); for (const auto& value : container) { // do something } } main() ne change pas! fun() change facilite la maintenance de code auto
  • 29. 22 • permet d’adopter un style de programmation fonctionnelle ‣ Scala : val x = fun() ‣ C++ : const auto x = fun(); • auto utilise les règles de déduction des templates ‣ sauf pour le cas des listes d’initialisation (initializer_list) auto
  • 30. 23 const auto x = foo(); void* _ = x; error: cannot initialize a variable of type 'void *' with an lvalue of type 'TYPE'   void* _ = x;         ^   ~ 1 error generated. auto connaître le type déduit (tout compilateur)
  • 31. Initialisation uniformisée 24 struct foo {}; struct bar { bar(foo){} }; int main() { // function declaration or variable definition? bar b(foo()); } “most vexing parse” • define variable b of type bar with an instance of foo; or • declare function b which returns a bar and takes a function with no parameter and which returns a foo
  • 32. 25 Initialisation uniformisée struct foo {}; struct bar { bar(foo){} }; int main() { // add parentheses to declare a variable bar b((foo())); } “most vexing parse”
  • 33. 26 struct foo {}; struct bar { bar(foo){} }; int main() { // brace initializer bar b{foo{}}; // better auto b1 = bar{foo{}}; } solution : utiliser la syntaxe pour initialiser les agrégats : {} Initialisation uniformisée
  • 34. 27 struct foo { int i_; foo(int i) : i_(i) {} }; struct bar { int i_; }; int main() { const auto f = foo{42}; const auto b = bar{42}; } pour construire un objet Initialisation uniformisée
  • 35. 28 class foo { int i_; public: foo(int i) : i_(i) {} }; struct bar { int i_; }; int main() { const auto f = foo{42}; const auto b = bar{42}; } pour construire struct ou class Initialisation uniformisée
  • 36. 29 struct foo { int i; }; foo fun() { return {42}; } int main() { const auto f = fun(); } concision : on peut omettre le type de retour Initialisation uniformisée
  • 37. 29 struct foo { int i; }; foo fun() { return {42}; } int main() { const auto f = fun(); } concision : on peut omettre le type de retour pas de type explicite Initialisation uniformisée
  • 38. 30 #include <map> int main() { auto m = std::map<int,int>{}; // old style m.insert(std::make_pair(1, 2)); // new style m.insert({1, 2}); } exemple : insertion dans un conteneur associatif Initialisation uniformisée
  • 39. 31 double a, b, c; int x{a + b + c}; int y(a + b + c); int z = a + b + c; ne compile pas : perte de précision OK (mais mal) idem plus de sécurité Initialisation uniformisée
  • 40. 32 • Que choisir? • “{}” ‣ résistant au most vexing parse ‣ empêche la perte de précision ‣ utilisation plus cohérente • “()” ‣ ne casse pas les habitudes ‣ pas de confusion avec initializer_list (à suivre…) Initialisation uniformisée
  • 41. initializer_list 33 #include <iostream> #include <vector> int main() { const auto vec = std::vector<int>{1,2,3}; for (const auto& x : vec) { std::cout << x; } } même syntaxe que pour initialiser les agrégats
  • 42. initializer_list 33 #include <iostream> #include <vector> int main() { const auto vec = std::vector<int>{1,2,3}; for (const auto& x : vec) { std::cout << x; } } déclaration “naturelle” même syntaxe que pour initialiser les agrégats
  • 43. initializer_list 34 • C++11 définit un nouveau type ‣ std::initializer_list<T> ‣ #include <initializer_list> • Utilise la même syntaxe d'initialisation des tableaux C • {1,2,3} • Le contenu de la liste est copié
  • 44. initializer_list 35 #include <initializer_list> int main() { // deduced to std::initializer_list<int> const auto list = {1,2,2}; for (auto x : list) { // ... } } exception : auto + {} initializer_list auto utilise la déduction des templates
  • 45. initializer_list 35 #include <initializer_list> int main() { // deduced to std::initializer_list<int> const auto list = {1,2,2}; for (auto x : list) { // ... } } ne pas oublier! exception : auto + {} initializer_list auto utilise la déduction des templates
  • 46. initializer_list 36 void foo(std::initializer_list<int> list) { for (auto i : list) {} } foo({1,2,3}); initializer_list en paramètre
  • 47. initializer_list 36 void foo(std::initializer_list<int> list) { for (auto i : list) {} } foo({1,2,3}); passage par valeur initializer_list en paramètre
  • 48. initializer_list 37 struct bar { bar(std::initializer_list<int> list); }; const auto b = bar{1,2,3}; can be used to construct objects
  • 49. initializer_list 38 void foo(int i, std::initializer_list<int> li) { std::cout << i << " : "; for (auto x : li) std::cout << x << ","; } foo(42, {3,2,3,4}); utilisable avec d’autres arguments
  • 50. initializer_list 39 for (auto x : {1,2,3,4}) { std::cout << x << ','; } utilisable dans une boucle simplifiée
  • 51. initializer_list 40 #include <iostream> #include <initializer_list> struct bar { bar(std::initializer_list<int> list){std::cout << "listn";} bar(int) {std::cout << "intn";} }; int main() { const auto b = bar{1}; } qu’affiche le code suivant?
  • 52. initializer_list 41 #include <iostream> #include <vector> int main () { const auto v1 = std::vector<int>{2}; std::cout << v1.size(); const auto v2 = std::vector<int>(2); std::cout << v2.size(); } mais… qu’affiche le code suivant?
  • 53. initializer_list 42 • Permet de ‣ faciliter l’écriture des tests unitaires ‣ offrir une API élégante au code client ‣ … const auto v1 = std::vector<int>{1,2,3}; auto v2 = std::vector<int>{}; v2.reserve(3); v2.push_back(1); v2.push_back(2); v2.push_back(3); vs
  • 54. initializer_list 42 • Permet de ‣ faciliter l’écriture des tests unitaires ‣ offrir une API élégante au code client ‣ … const auto v1 = std::vector<int>{1,2,3}; auto v2 = std::vector<int>{}; v2.reserve(3); v2.push_back(1); v2.push_back(2); v2.push_back(3); vs bonus : plus d’immutabilité
  • 55. User-defined literals 43 unsigned long x0 = 0ul; long x1 = 0l; // etc. C++03 : il est possible de suffixer un littéral pour y appliquer des caractéristiques
  • 56. User-defined literals 44 long double operator"" _deg (long double x) { return x * 3.141592/180; } const auto x = 90.0_deg; pour convertir une valeur
  • 57. User-defined literals 44 long double operator"" _deg (long double x) { return x * 3.141592/180; } const auto x = 90.0_deg; ne pas oublier “_” pour convertir une valeur
  • 58. User-defined literals 45 struct foo { const unsigned long long x_; foo(unsigned long long x) : x_(x) {} }; foo operator"" _foo (unsigned long long n) { return {n}; } const auto f = 123_foo; pour construire un objet
  • 59. User-defined literals 46 void operator"" _print(const char* str, std::size_t) { std::cout << str; } "C++11 rocks!"_print; à partir de chaînes de caractères
  • 60. User-defined literals 47 struct point { //??? }; // Yaye! const auto p = 3_x + 5_y; comment obtenir cette construction?
  • 61. User-defined literals 48 struct x_type{unsigned long long value;}; struct y_type{unsigned long long value;}; x_type operator"" _x(unsigned long long value) {return {value};} y_type operator"" _y(unsigned long long value) {return {value};} struct point { unsigned long long x_, y_; private: point(const x_type& x, const y_type& y) : x_(x.value), y_(y.value) {} friend point operator+(const x_type&, const y_type&); }; point operator+(const x_type& x, const y_type& y) {return {x, y};}; // later... const auto p = 3_x + 5_y;
  • 62. String literals 49 const auto utf8 = u8"UTF-8 string. u2705n”; std::cout << utf8; const auto utf16 = u8"UTF-16 string.n”; std::wcout << utf16; UTF-8 string. ✅ UTF-16 string. Gestion UTF-8, UTF-16 et UTF-32
  • 63. Binary literals 50 const auto b = 0b00101010; std::cout << b; // 42 C++14 uniquement
  • 64. Séparateur ‘ 51 const auto big_value = 64'000'000'000'000'000; facilite la lecture des grandes constantes const auto b = 0b0010'1010;
  • 65. Raw string literals 52 const auto raw = R"(@ tLook Ma, no tabs! some text )"; const auto escaped = "@n" "somen" "textn"; int main() { std::cout << raw; std::cout << "--------------n"; std::cout << escaped; } @ tLook Ma, no tabs! some text -------------- @ some text
  • 66. enum class 53 int main() { enum e{pink, white, orange, brown}; const auto white = 0ul; } error: redefinition of 'white' as different kind of symbol   const auto white = 0ul;              ^ note: previous definition is here   enum e{pink, white, orange, brown};                ^ enum C++03 : pollution de l’espace de nommage
  • 67. enum class 53 int main() { enum e{pink, white, orange, brown}; const auto white = 0ul; } ne compile pas error: redefinition of 'white' as different kind of symbol   const auto white = 0ul;              ^ note: previous definition is here   enum e{pink, white, orange, brown};                ^ enum C++03 : pollution de l’espace de nommage
  • 68. enum class 54 enum e {pink, white, orange, brown}; if (pink < 99.3) { // ... } enum C++03 : conversion implicite dangereuse
  • 69. enum class 54 enum e {pink, white, orange, brown}; if (pink < 99.3) { // ... } enum C++03 : conversion implicite dangereuse compile, mais est-ce vraiment une bonne chose?
  • 70. enum class 55 int main() { enum class e{pink, white, orange, brown}; const auto white = 0ul; const auto e0 = e::white; } enum class créé une nouvelle portée
  • 71. enum class 55 int main() { enum class e{pink, white, orange, brown}; const auto white = 0ul; const auto e0 = e::white; } enum class créé une nouvelle portée accès à la portée de e
  • 72. enum class 56 enum class e{pink, white, orange, brown}; // use std::underlying_type<e>::type to find enum’s type type par défaut sous-jacent : int
  • 73. enum class 57 enum class e : unsigned long {pink = 0, white, orange, brown = 0xFFFFFFFFFFFFFFFF}; // use std::underlying_type<e>::type to find enum’s type changer le type sous-jacent
  • 74. enum class 58 • C++03 : il n’y a pas de type par défaut pour énumération ‣ on est donc obligé de la mettre dans les headers ‣ recompilation en cascade s’il faut rajouter un champ • C++11 : on peut faire une pré-déclaration ‣ définition dans une unité de compilation séparée ‣ pas de recompilation en cascade
  • 75. nullptr 59 void f(int) {std::cout << "f(int)";} void f(void*){std::cout << "f(void*)";} f(0); f(NULL); error: call to 'f' is ambiguous   f(NULL);   ^ note: candidate function void f(int)  {std::cout << "f(int)";}      ^ note: candidate function void f(void*){std::cout << "f(void*)";} f(int) f(int) clang/gcc Visual Studio
  • 76. nullptr 60 void f(int) {std::cout << "f(int)";} void f(void*){std::cout << "f(void*)";} f(0); f(nullptr); f(int) f(void*) moins d’ambiguité
  • 77. nullptr 61 const auto x = f(); if (x == 0) { // ... } plus de clarté const auto x = f(); if (x == nullptr) { // ... } vs
  • 78. nullptr 61 const auto x = f(); if (x == 0) { // ... } plus de clarté const auto x = f(); if (x == nullptr) { // ... } vs intention plus claire
  • 79. nullptr 62 type de nullptr void f(int) {std::cout << "f(int)";} void f(void*) {std::cout << "f(void*)";} void f(std::nullptr_t) {std::cout << "f(nullptr_t)";} f(nullptr);
  • 80. alignas 63 alignas(16) int a; alignas(32768) int b; std::cout << &a; std::cout << &b; 0x7fff58d2ffe0 0x7fff58d28000 contrôler l’alignement mémoire
  • 81. alignof 64 std::cout << alignof(int); std::cout << alignof(long); std::cout << alignof(char); std::cout << alignof(char*); connaître l’alignement mémoire (d’un type) 4 8 1 8
  • 82. Classes • Délégation de constructeurs • Héritage des constructeurs des classes de base • Initialisation directe des attributs • Contrôle de l’héritage • Contrôle explicite des méthodes supprimées 65
  • 83. Classes 66 délégation de constructeurs (1) struct foo { const int x_; foo(int x) : x_{x} {} foo() : foo{42} {} };
  • 84. Classes 66 délégation de constructeurs (1) struct foo { const int x_; foo(int x) : x_{x} {} foo() : foo{42} {} }; délégation
  • 85. Classes 67 délégation de constructeurs (2) struct foo { const int x_; foo(int x = 42) : x_{x} {} }; on pourrait utiliser les arguments par défaut problème : dans l’interface de la classe
  • 86. Classes 68 héritage des constructeurs (1) : C++03 struct base { const int x_; base(int x) : x_(x) {} }; struct foo : public base { foo(int x) : base(x) {} };
  • 87. Classes 68 héritage des constructeurs (1) : C++03 struct base { const int x_; base(int x) : x_(x) {} }; struct foo : public base { foo(int x) : base(x) {} }; appel explicite
  • 88. Classes 69 héritage des constructeurs (2) : C++11 struct base { const int x_; base(int x) : x_(x) {} }; struct foo : public base { using base::base; };
  • 89. Classes 69 héritage des constructeurs (2) : C++11 struct base { const int x_; base(int x) : x_(x) {} }; struct foo : public base { using base::base; }; hérite de tous les constructeurs de base
  • 90. Classes 70 initialisation directe des attributs struct foo { const int x_ = 33; foo(int x) : x_(x) {} foo() {} };
  • 91. Classes 70 initialisation directe des attributs struct foo { const int x_ = 33; foo(int x) : x_(x) {} foo() {} }; valeur par défaut utilisée par tous les constructeurs
  • 92. Classes 71 contrôle de l’héritage avec final struct foo final {}; struct bar : foo {};
  • 93. Classes 71 contrôle de l’héritage avec final struct foo final {}; struct bar : foo {}; ne compile pas error: base 'foo' is marked 'final' struct bar : foo {};              ^
  • 94. Classes 72 contrôle de l’héritage avec override (1) struct base { virtual void operator()(float x) const {std::cout << "base " << x;} }; struct derived : public base { virtual void operator()(int x) const {std::cout << "derived " << x;} }; const auto d = derived{}; auto x = 33.3; d(x);
  • 95. Classes 72 contrôle de l’héritage avec override (1) struct base { virtual void operator()(float x) const {std::cout << "base " << x;} }; struct derived : public base { virtual void operator()(int x) const {std::cout << "derived " << x;} }; const auto d = derived{}; auto x = 33.3; d(x); affichage?
  • 96. Classes 73 contrôle de l’héritage avec override (2) struct base { virtual void operator()(float x) const; }; struct derived : public base { virtual void operator()(int x) const override; };
  • 97. Classes 73 contrôle de l’héritage avec override (2) struct base { virtual void operator()(float x) const; }; struct derived : public base { virtual void operator()(int x) const override; }; error: 'operator()' marked 'override' but does not override any member functions   virtual void operator()(int x) const                ^
  • 98. Classes 74 contrôle des fonctions membres avec default / delete (1) struct non_copyable { non_copyable(){} private: non_copyable(const non_copyable&); non_copyable& operator=(const non_copyable&); }; int main() { const auto nc = non_copyable{}; } error: calling a private constructor of class 'non_copyable'   const auto nc = non_copyable{};                   ^
  • 99. Classes 75 struct non_copyable { non_copyable() = default; non_copyable(const non_copyable&) = delete; non_copyable& operator=(const non_copyable&) = delete; }; int main() { const auto nc = non_copyable{}; } error: call to deleted constructor of 'const non_copyable'   const auto nc = non_copyable{};              ^    ~~~~~~~~~~~~~~ note: 'non_copyable' has been explicitly marked deleted here   non_copyable(const non_copyable&) = delete; contrôle des fonctions membres avec default / delete (2)
  • 100. Classes 76 struct base { virtual void operator()(int x) const; }; struct derived : public base { virtual void operator()(int x) const override; }; int main() { const auto override = 0ul; const auto final = 0ul; } contrôle des fonctions membres avec default / delete (3)
  • 101. Classes 76 struct base { virtual void operator()(int x) const; }; struct derived : public base { virtual void operator()(int x) const override; }; int main() { const auto override = 0ul; const auto final = 0ul; } pas des mots-clefs contrôle des fonctions membres avec default / delete (3)
  • 102. delete 77 void foo(int){}; void foo(long) = delete; void foo(double) = delete; foo(42); // OK foo(42l); // ERROR foo(42.0); // ERROR permet aussi d’empêcher certaines surcharges error: call to deleted function 'foo'   foo(42l);   ^~~ note: candidate function has been explicitly deleted void foo(long) = delete;      ^ note: candidate function void foo(int){};      ^ note: candidate function has been explicitly deleted void foo(double) = delete;      ^
  • 103. Rvalues references • Ajout majeur au C++ • Travailler explicitement avec les temporaires • Éviter des copies inutiles ‣ move semantics • Perfect forwarding ‣ construire en place ‣ généricité améliorée ‣ … 78
  • 104. Rvalues references • lvalues ‣ un objet qui occupe une place identifiable en mémoire - qui a une adresse • rvalues ‣ un objet qui n’occupe pas une place identifiable en mémoire - qui n’a pas d’adresse : temporaire 79 lvalue = rvalue lvalue = lvalue rvalue = lvalue int x = 42 int x = y 42 = ...
  • 105. Rvalues references 80 int foo() {return 2;} int main() { foo() = 2; } error: lvalue required as left operand of assignment foo() = 2; ^
  • 106. Rvalues references 81 struct foo { foo() { std::cout << “foo()n”; } foo(const foo&) { std::cout << "foo(const foo&)n”; } foo& operator=(const foo&) { std::cout << "operator=(const foo&)n”; return *this; } }; foo bar() {return {};} const auto f0 = foo{}; auto f1 = bar(); f1 = bar(); interlude : copy elision
  • 107. Rvalues references 81 struct foo { foo() { std::cout << “foo()n”; } foo(const foo&) { std::cout << "foo(const foo&)n”; } foo& operator=(const foo&) { std::cout << "operator=(const foo&)n”; return *this; } }; foo bar() {return {};} const auto f0 = foo{}; auto f1 = bar(); f1 = bar(); interlude : copy elision ?
  • 108. Rvalues references 82 comment éviter la copie? (1) foo* bar() {return new foo{};} auto f1 = bar(); // later... f1 = bar(); • Retour par pointeur ‣ Coût de l’allocation ‣ Qui est responsable du pointeur?
  • 109. Rvalues references 83 comment éviter la copie? (2) void bar(foo*); auto f = foo{}; bar(&f); • Passage par pointeur ou référence en paramètre • Quid des factories?
  • 110. Rvalues references 84 comment modifier un temporaire? void bar(foo&); //... auto f = foo{}; bar(f1); bar(foo{}); utile pour un objet fonction avec état (cache, etc.)
  • 111. Rvalues references 84 comment modifier un temporaire? void bar(foo&); //... auto f = foo{}; bar(f1); bar(foo{}); ne compile pas utile pour un objet fonction avec état (cache, etc.)
  • 112. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42});
  • 113. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42}); foo&& : rvalue reference
  • 114. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42}); foo&& : rvalue reference foo{42} : rvalue expression
  • 115. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42}); foo&& : rvalue reference foo{42} : rvalue expression f : lvalue expression on peut prendre l’adresse de f
  • 116. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42}); foo&& : rvalue reference foo{42} : rvalue expression f : lvalue expression on peut prendre l’adresse de f le passage en paramètre “nomme” le temporaire celui-ci devient une lvalue : on peut prendre son adresse sur la pile
  • 117. Rvalues references 86 une rvalue reference n’accepte que des rvalue expressions struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... auto f = foo{42}; bar(f);
  • 118. Rvalues references 86 une rvalue reference n’accepte que des rvalue expressions struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... auto f = foo{42}; bar(f); erreur : f n’est pas une rvalue expression
  • 119. Rvalues references 87 ref-qualifiers struct foo { void operator()() const && { std::cout << "&&n"; } void operator()() const & { std::cout << "&n"; } }; //... const auto f = foo{}; f(); foo{}();
  • 120. Rvalues references 87 ref-qualifiers struct foo { void operator()() const && { std::cout << "&&n"; } void operator()() const & { std::cout << "&n"; } }; //... const auto f = foo{}; f(); foo{}(); en tant que rvalue en tant que lvalue
  • 121. Move semantics • Permet d’exprimer le “déplacement” d’une ressource • Permet d’exprimer le changement de propriétaire d’une entité non copiable ‣ mutex, fichier, … • Utilisation des rvalues references • Utilisation de std::move() ‣ instruction au compilateur ‣ ne génère aucun code 88
  • 124. Move semantics 90 struct foo { some_type* ressource; foo& operator=(const foo& rhs) { // destroy this->ressource // clone rhs.ressource // attach this cloned ressource to this->ressource } }; auto f1 = foo{}; auto f2 = foo{}; // later... f2 = f1; copie
  • 125. Move semantics 90 struct foo { some_type* ressource; foo& operator=(const foo& rhs) { // destroy this->ressource // clone rhs.ressource // attach this cloned ressource to this->ressource } }; auto f1 = foo{}; auto f2 = foo{}; // later... f2 = f1; copie O(n)
  • 126. Move semantics 91 auto f1 = foo{}; //... auto f2 = std::move(f1); // now f1 is “invalid” transfert de ressource (1) move() transforme une lvalue expression en rvalue expression
  • 127. Move semantics 92 struct foo { some_type* ressource; foo& operator=(foo&& rhs) { // destroy this->ressource // copy rhs.ressource pointer to this->ressource } }; auto f1 = foo{}; auto f2 = foo{}; //... f2 = std::move(f1); transfert de ressource (2)
  • 128. Move semantics 92 struct foo { some_type* ressource; foo& operator=(foo&& rhs) { // destroy this->ressource // copy rhs.ressource pointer to this->ressource } }; auto f1 = foo{}; auto f2 = foo{}; //... f2 = std::move(f1); transfert de ressource (2) O(1)
  • 129. Move semantics 92 struct foo { some_type* ressource; foo& operator=(foo&& rhs) { // destroy this->ressource // copy rhs.ressource pointer to this->ressource } }; auto f1 = foo{}; auto f2 = foo{}; //... f2 = std::move(f1); transfert de ressource (2) O(1) mais pas toujours…
  • 130. Move semantics 93 struct foo { foo() = default; foo(const foo&) = default; foo(foo&&) = delete; }; int main() { const auto f = foo{}; }
  • 131. Move semantics 93 struct foo { foo() = default; foo(const foo&) = default; foo(foo&&) = delete; }; int main() { const auto f = foo{}; } ne compile pas
  • 132. Move semantics 94 struct foo {}; foo return_by_value() { const auto f = foo{}; return f; } void take_by_value(foo) {} auto f1 = foo{}; auto f2 = f1; auto f3 = std::move(f1); take_by_value(f2); take_by_value(std::move(f2)); auto f4 = return_by_value(); f1 = return_by_value(); quelles sont les opérations appelées?
  • 133. Move semantics 95 transfert de propriété struct foo { some_type ressource; // forbid copy foo(const foo&) = delete; foo& operator=(const foo&) = delete; foo(foo&& rhs) noexcept { // 1. acquire ownership of rhs.ressource // 2. free rhs from its ownership } foo& operator=(foo&&) noexcept { // 1. release ownership of current ressource // 2. acquire ownership of rhs.ressource // 3. free rhs from its ownership } };
  • 134. Move semantics 96 struct foo; foo bar() { auto f = foo{}; // later... return std::move(f); } std::move en retour d’une fonction
  • 135. Move semantics 96 struct foo; foo bar() { auto f = foo{}; // later... return std::move(f); } mauvaise idée std::move en retour d’une fonction
  • 136. Move semantics 97 const rvalue references? void bar(const foo&& f); // what for if we can't move f? void bar(const foo&); // read only réellement utile pour interdire tout usage des rvalues struct foo { foo() {}; foo(foo&&) = delete; foo(const foo&&) = delete; }; // later... const foo f0; foo f1(std::move(f0)); void bar(const foo&& f); // what for if we can't move f? void bar(const foo&); // read only
  • 137. Move semantics 98 struct foo; foo f1; foo f2; std::swap(f1, f2); C++03 vs C++11 foo() foo() foo(foo&&) operator=(foo&&) operator=(foo&&) foo() foo() foo(const foo&) operator=(const foo&) operator=(const foo&) C++03 C++11
  • 138. decltype 99 permet de connaître le type d’une expression int* foo(); using ty0 = decltype(foo); print_type<ty0>(); using ty1 = decltype(foo()); print_type<ty1>(); void print_type() [T = int *()] void print_type() [T = int *]
  • 139. trailing return type 100 auto foo() -> int { return 42; } std::cout << foo(); type de retour après les paramètres
  • 140. trailing return type 101 template <typename T1, typename T2> ??? add(const T1& x, const T2& y) { return x + y; } si le type de retour dépend des paramètres template <typename T1, typename T2> auto add(const T1& x, const T2& y) -> decltype(x+y) { return x + y; }
  • 141. trailing return type 102 double (*get_fun2(bool arg))(double) { if (arg) return std::cos; else return std::sin; } plus de lisibilité auto get_fun(bool arg) -> double(*)(double) { if (arg) return std::cos; else return std::sin; } vs
  • 142. trailing return type 103 C++14 : on peut se passer du type de retour template <typename T1, typename T2> auto add(const T1& x, const T2& y) -> decltype(x+y) { return x + y; }
  • 143. trailing return type 104 C++14 : on peut se passer du type de retour mais pas toujours… auto get_fun(bool arg) { if (arg) return std::cos; else return std::sin; } error: cannot deduce return type 'auto' from returned value of type '<overloaded function type>'   if (arg) return std::cos;
  • 144. 105 lambdas struct print1 { void operator()(int x) const { std::cout << x << 'n'; } }; void print2(int x) { std::cout << x << 'n'; } const auto v = {1,2,3}; std::for_each(begin(v), end(v), print1{}); std::for_each(begin(v), end(v), print2); programmation fonctionnelle : objets fonctions et fonctions en argument
  • 145. lambdas 106 const auto v = {1,2,3}; std::for_each( begin(v), end(v) , [](int x){std::cout << x << ‘n';} ); const auto v = {1,2,3}; const auto print = [](int x){std::cout << x << 'n';}; std::for_each(begin(v), end(v), print); par l’exemple const auto fun = []{return 42;}; const auto x = fun(); std::cout << x << 'n';
  • 146. lambdas 107 const auto print = [](int x){std::cout << x;}; print_type<decltype(print)>(); void print_type() [with T = const main()::<lambda(int)>] type d’un lambda il n’y pas de type pour les lambdas en tant que tel auto est quasi-obligatoire si on veut stocker un lambda ou presque…
  • 147. lambdas 108 anatomie d’un lambda [capture](params) -> ret_type {body} comment “capturer” l’environnement corps de la fonction peut-être omis type de retour si nécessaire
  • 148. lambdas 109 spécification du type de retour (1) struct foo {}; struct bar : public foo {}; struct baz : public foo {}; const auto foo_maker = [](bool value) { if (value) return new bar{}; else return new baz{}; }; const auto ptr = foo_maker(true); error: return type 'baz *' must match previous return type 'bar *' when lambda expression has unspecified explicit return type                              else       return new baz{};                                         ^
  • 149. lambdas 110 spécification du type de retour (2) struct foo {}; struct bar : public foo {}; struct baz : public foo {}; const auto foo_maker = [](bool value) -> foo* { if (value) return new bar{}; else return new baz{}; }; const auto ptr = foo_maker(true);
  • 150. lambdas 110 spécification du type de retour (2) struct foo {}; struct bar : public foo {}; struct baz : public foo {}; const auto foo_maker = [](bool value) -> foo* { if (value) return new bar{}; else return new baz{}; }; const auto ptr = foo_maker(true); type de retour
  • 151. lambdas 111 capture de l’environnement (1) [] ne capture rien [&] tout par référence [=] tout par valeur [this] capture this [=,&b] copie tout, mais reférence b [&a, b] référence a, copie b environnement = toutes les variables de la portée englobante
  • 152. lambdas 111 capture de l’environnement (1) [] ne capture rien [&] tout par référence [=] tout par valeur [this] capture this [=,&b] copie tout, mais reférence b [&a, b] référence a, copie b environnement en “lecture seule” environnement = toutes les variables de la portée englobante const auto x = 42u; []{std::cout << x;}(); // OK auto x = 40u; []{x += 2;}(); // ERROR
  • 153. struct foo { int x_; int bar(int y) { return [this](int y) {return x_ + y;} (y); } }; std::cout << foo{40}.bar(2); lambdas 112 auto x = 40u; [&x](int y){x += y;}(2); std::cout << x; auto a = 40u; [&](int b){a += b;}(2); std::cout << x; capture de l’environnement (2)
  • 154. struct foo { int x_; int bar(int y) { return [this](int y) {return x_ + y;} (y); } }; std::cout << foo{40}.bar(2); lambdas 112 auto x = 40u; [&x](int y){x += y;}(2); std::cout << x; auto a = 40u; [&](int b){a += b;}(2); std::cout << x; capture de l’environnement (2)
  • 155. auto x = 44u; [=]{x -= 2;}(); lambdas 113 error: cannot assign to a variable captured by copy in a non-mutable lambda   [=]{x -= 2;}();       ~ ^ auto x = 44u; [=]() mutable {x -= 2;}(); capture de l’environnement (3)
  • 156. auto x = 44u; [=]{x -= 2;}(); lambdas 113 error: cannot assign to a variable captured by copy in a non-mutable lambda   [=]{x -= 2;}();       ~ ^ auto x = 44u; [=]() mutable {x -= 2;}(); obligatoire capture de l’environnement (3)
  • 157. lambdas 114 “fermeture” équivalente à un objet fonction (1) struct closure { double& capture_; int operator()(int x, int& y) const { return (x + y) * capture_; } closure() = delete; closure& operator=(const closure&) = delete; closure(const closure& ) = default; closure(closure&& ) = default; ~closure() = default; }; auto fun0 = [&d](int x, int& y){return (x + y) * d;};
  • 158. lambdas 114 “fermeture” équivalente à un objet fonction (1) struct closure { double& capture_; int operator()(int x, int& y) const { return (x + y) * capture_; } closure() = delete; closure& operator=(const closure&) = delete; closure(const closure& ) = default; closure(closure&& ) = default; ~closure() = default; }; auto fun0 = [&d](int x, int& y){return (x + y) * d;}; d’où le mutable
  • 159. lambdas 115 auto d = 0.0; auto fun1 = fun0; // OK fun1 = fun0; // KO no copy operator using ty = decltype(fun0); auto fun2 = ty{}; // KO no default ctor auto fun0 = [&d](int x, int& y){return (x + y) * d;}; “fermeture” équivalente à un objet fonction (2)
  • 160. lambdas 116 en paramètre d’un template template <typename F, typename T> void apply(T x) { F{}(x); } auto fun = [](int x){x += 1;}; apply<decltype(fun)>(0);
  • 161. lambdas 117 attention aux références invalides auto mk_fun() -> std::function<void (int&)> { auto i = 33u; return [&](int& j){j += i;}; } int main() { auto j = 2; const auto fun = mk_fun(); fun(j); // Doomed to failure }
  • 162. lambdas 117 attention aux références invalides auto mk_fun() -> std::function<void (int&)> { auto i = 33u; return [&](int& j){j += i;}; } int main() { auto j = 2; const auto fun = mk_fun(); fun(j); // Doomed to failure } portée locale à mk_fun
  • 163. lambdas 117 attention aux références invalides auto mk_fun() -> std::function<void (int&)> { auto i = 33u; return [&](int& j){j += i;}; } int main() { auto j = 2; const auto fun = mk_fun(); fun(j); // Doomed to failure } portée locale à mk_fun lecture de i locale à mk_fun
  • 164. lambdas 118 C++14 : paramètres génériques const auto add = [](const auto& x, const auto& y){return x + y;}; add(1,2); add(std::string{"1"}, std::string{"2"});
  • 165. lambdas 119 au service de l’immutabilité const auto read_only = [&] { std::vector<int> res; // super-complex initialisation return res }(); read_only.push_back(3); // nope, won’t do auto read_only = std::vector<int>{}; // super-complex initialisation // ...later // damned, still mutable! read_only.push_back(3);
  • 166. noexcept • C++03 ‣ il faut lister dans la signature d’une fonction les exceptions qu’elle peut lever (throw (…)) ‣ difficile à maintenir ‣ pas ou peu d’aide des compilateurs • C++11 ‣ seule alternative : une fonction peut ou ne peut pas lever d’exception ‣ avantage majeur : le compilateur a plus d’opportunités d’optimisations 120
  • 167. noexcept 121 void foo() noexcept { // shall not throw any exception } struct foo { void operator()() const noexcept { // shall not throw any exception } }; sur fonctions libres ou membres
  • 168. noexcept 122 opportunités d’optimisation auto vec = std::vector<foo>{}; const auto f = foo{}; vec.push_back(f); • Si vec doit agrandir son stockage interne ‣ C++03 : recopie - si une exception est lancée pendant la copie, vec original n’est pas modifié (strong guarantee) ‣ C++11 : strong guarantee à tenir - move si foo(foo&&) noexcept - copie sinon
  • 169. noexcept 123 noexcept conditionnel (1) void bar() noexcept { // shall not throw any exception } void foo() noexcept(noexcept(bar())) { bar(); }
  • 170. noexcept 124 noexcept conditionnel (2) struct bar { void operator()(int) noexcept {} }; struct baz { void operator()(int){} }; template <typename Fun> void foo(int x) noexcept(noexcept(Fun{}(x))) { Fun{}(x); } foo<bar>(33); foo<baz>(42);
  • 171. noexcept 125 noexcept appliqué aux lambdas const auto lambda = [](int x) noexcept {return x + 40;}; std::cout << lambda(2);
  • 172. • Destructeurs, operator delete et operator delete[] : noexcept par défaut • C’est une affirmation forte ‣ déclarer une fonction noexcept, puis plus tard enlever cette spécification peut casser le code client • Important pour ‣ foo(foo&&) ‣ foo& operator=(foo&&) ‣ swap(foo&, foo&) ‣ fonctions de calcul (sans allocations dynamiques)? ‣ …? 126 noexcept
  • 173. constexpr 127 • const : spécifier des interfaces - foo(const std::vector<int>&); • constexpr : spécifier ce qui est utilisable dans des expressions constantes (et donc possiblement évaluées à la compilation) - tout ce qui est marqué constexpr doit pouvoir produire un résultat constant • Applicable aux objets et aux fonctions Visual Studio 2013
  • 174. constexpr 128 auto sz = 3; // ERROR: sz's value not known at compilation constexpr auto sz1 = sz; // ERROR: sz's value not known at compilation auto array1 = std::array<int, sz>{}; // OK: 10 is a compile-time constant constexpr auto sz2 = 10; // OK: sz2 is constexpr auto array2 = std::array<int, sz2>{}; objets (1)
  • 175. constexpr 129 const auto sz = 3; // OK: sz's value is known at compilation constexpr auto sz1 = sz; // OK: sz's value is known at compilation auto array1 = std::array<int, sz>{}; auto x = 3; const auto sz = x; // ERROR: sz's value not known at compilation constexpr auto sz1 = sz; // ERROR: sz's value not known at compilation auto array1 = std::array<int, sz>{}; objets (2)
  • 176. constexpr 130 fonctions constexpr int foo(int a) { return a + 1; } constexpr auto x = foo(42); auto runtime_value = 0u; std::cin >> runtime_value; auto y = foo(runtime_value); fonction expression constante expression non-constante constexpr ✓ ✓ non-constexpr ✕ ✓
  • 177. constexpr 131 C++11 seulement une expression autorisée constexpr int fac(int x) { return x <= 1 ? 1 : x * fac(x-1); } constexpr int fac(int x) { auto res = 1; for (auto i = 1; i <= x; ++i) { res *= i; } return res; } C++14 plusieurs instructions autorisées
  • 178. constexpr 132 classes struct foo { int data; constexpr foo(int d) : data(d) {} constexpr int operator()() const {return data + 1;} constexpr operator int() const {return data;} }; auto f0 = foo{42}; constexpr auto f1 = foo{33}; auto i0 = f0(); constexpr auto i1 = f1(); constexpr auto i2 = static_cast<int>(f1); auto i3 = static_cast<int>(f1);
  • 179. constexpr 132 classes struct foo { int data; constexpr foo(int d) : data(d) {} constexpr int operator()() const {return data + 1;} constexpr operator int() const {return data;} }; auto f0 = foo{42}; constexpr auto f1 = foo{33}; auto i0 = f0(); constexpr auto i1 = f1(); constexpr auto i2 = static_cast<int>(f1); auto i3 = static_cast<int>(f1); implicite en C++11 à mettre en C++14
  • 180. constexpr 133 unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } constexpr unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } en pratique (clang)…
  • 181. constexpr 133 unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } constexpr unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } pushq %rbp movq %rsp, %rbp movl $0x78, %eax popq %rbp retq en pratique (clang)…
  • 182. constexpr 133 unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } constexpr unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } pushq %rbp movq %rsp, %rbp movl $0x78, %eax popq %rbp retq movdqa %xmm0, %xmm1 movhlps %xmm1, %xmm1 pshufd $0x31, %xmm0, %xmm2 pmuludq %xmm1, %xmm0 pshufd $0x31, %xmm1, %xmm1 pmuludq %xmm2, %xmm1 shufps $-0x78, %xmm1, %xmm0 pshufd $-0x28, %xmm0, %xmm0 pshufd $0x1, %xmm0, %xmm1 pshufd $0x31, %xmm0, %xmm2 pmuludq %xmm0, %xmm2 pmuludq %xmm0, %xmm1 shufps $-0x78, %xmm2, %xmm1 pshufd $-0x28, %xmm1, %xmm0 movd %xmm0, %eax cmpl %edx, %r8d je 0x100000f5d nopw %cs:(%rax,%rax) imull %edi, %eax leal -0x1(%rdi), %ecx cmpl $0x1, %ecx movl %ecx, %edi ja 0x100000f50 popq %rbp retq nop pushq %rbp movq %rsp, %rbp movl $0x78, %eax popq %rbp retq en pratique (clang)…
  • 183. constexpr 133 unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } constexpr unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } pushq %rbp movq %rsp, %rbp movl $0x78, %eax popq %rbp retq pushq %rbp movq %rsp, %rbp movl $0x1, %eax cmpl $0x2, %edi jb 0x100000f5d leal -0x1(%rdi), %r8d movl %r8d, %ecx en pratique (clang)…
  • 184. constexpr 133 unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } constexpr unsigned int f(unsigned int n) { return n <= 1 ? 1 : n * f(n-1); } int main() { return f(5); } Évaluation à l’exécution Évaluation à la compilation en pratique (clang)…
  • 185. static_assert 134 #include <type_traits> template <typename T> constexpr bool is_power_of_two(T x) { static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value , "Integral and unsigned type expected"); return x and ((x & (x-1)) == 0); } int main() { is_power_of_two(-2); } faire échouer la compilation sur un message clair error: static_assert failed "Integral and unsigned type expected"   static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value   ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • 186. static_assert 134 #include <type_traits> template <typename T> constexpr bool is_power_of_two(T x) { static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value , "Integral and unsigned type expected"); return x and ((x & (x-1)) == 0); } int main() { is_power_of_two(-2); } faire échouer la compilation sur un message clair error: static_assert failed "Integral and unsigned type expected"   static_assert( std::is_integral<T>::value and std::is_unsigned<T>::value   ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression constante requise
  • 188. Généricité 136 struct foo_vector { foo* data; unsigned int sz; void push_back(const foo& x) { data[sz++] = x; } }; une nécessité pour les structures de données… auto int_vec = int_vector{}; auto foo_vec = foo_vector{}; int_vec.push_back(1); foo_vec.push_back(foo{}); struct int_vector { int* data; unsigned int sz; void push_back(const int& x) { data[sz++] = x; } };
  • 189. Généricité 137 struct int_vector { int* data; unsigned int sz; void push_back(const int& x) { data[sz++] = x; } }; une nécessité pour les structures de données… struct foo_vector { foo* data; unsigned int sz; void push_back(const foo& x) { data[sz++] = x; } };
  • 190. Généricité 138 template <typename T> struct vector { T* data; unsigned int sz; void push_back(const T& x) { data[sz++] = x; } }; une nécessité pour les structures de données… auto int_vec = vector<int>{}; auto foo_vec = vector<foo>{}; int_vec.push_back(1); foo_vec.push_back(foo{});
  • 191. Généricité 138 template <typename T> struct vector { T* data; unsigned int sz; void push_back(const T& x) { data[sz++] = x; } }; une nécessité pour les structures de données… auto int_vec = vector<int>{}; auto foo_vec = vector<foo>{}; int_vec.push_back(1); foo_vec.push_back(foo{}); “instanciation” du type générique vector avec un entier
  • 192. Généricité 139 int sum(const std::vector<int>& vec) { auto acc = int{}; for (const auto& x : vec) acc = acc + x; return acc; } une nécessité pour les algorithmes… const auto vec0 = std::vector<int>{1,2,3}; const auto s0 = sum(vec0); const auto vec1 = std::vector<foo>{1,2,3}; const auto s1 = sum(vec1); struct foo; foo operator+(const foo&, const foo&); foo sum(const std::vector<foo>& vec) { auto acc = foo{}; for (const auto& x : vec) acc = acc + x; return acc; }
  • 193. Généricité 140 int sum(const std::vector<int>& vec) { auto acc = int{}; for (const auto& x : vec) acc = acc + x; return acc; } une nécessité pour les algorithmes… foo sum(const std::vector<foo>& vec) { auto acc = foo{}; for (const auto& x : vec) acc = acc + x; return acc; }
  • 194. Généricité 141 template <typename T> T sum(const std::vector<T>& vec) { auto acc = T{}; for (const auto& x : vec) { acc = acc + x; } return acc; } une nécessité pour les algorithmes… const auto vec0 = std::vector<int>{1,2,3}; const auto s0 = sum(vec0); const auto vec1 = std::vector<foo>{1,2,3}; const auto s1 = sum(vec1);
  • 195. Généricité 141 template <typename T> T sum(const std::vector<T>& vec) { auto acc = T{}; for (const auto& x : vec) { acc = acc + x; } return acc; } rien n’a changé! une nécessité pour les algorithmes… const auto vec0 = std::vector<int>{1,2,3}; const auto s0 = sum(vec0); const auto vec1 = std::vector<foo>{1,2,3}; const auto s1 = sum(vec1);
  • 196. Structures templates 142 template <typename T> struct foo { T x_; foo(const T& x) : x_(x) {} const T& x() const {return x_;} T& x() {return x_;} }; auto f_int = foo<int>{42}; f_int.x() += 2; auto f_char = foo<char>{'a'}; f_char.x() = 'b';
  • 197. Structures templates 142 template <typename T> struct foo { T x_; foo(const T& x) : x_(x) {} const T& x() const {return x_;} T& x() {return x_;} }; paramètre générique : c’est un type, pas une valeur auto f_int = foo<int>{42}; f_int.x() += 2; auto f_char = foo<char>{'a'}; f_char.x() = 'b';
  • 198. Structures templates 142 template <typename T> struct foo { T x_; foo(const T& x) : x_(x) {} const T& x() const {return x_;} T& x() {return x_;} }; paramètre générique : c’est un type, pas une valeur accès au type dans toute la classe auto f_int = foo<int>{42}; f_int.x() += 2; auto f_char = foo<char>{'a'}; f_char.x() = 'b';
  • 199. Fonctions templates 143 struct foo{}; template <typename T, typename U> void fun0(const T&, const U&); template <typename T, typename U> void fun1(const T&); fun0(0, foo{}); fun1<int, foo>(0); déduction automatique à partir des arguments
  • 200. Fonctions templates 143 struct foo{}; template <typename T, typename U> void fun0(const T&, const U&); template <typename T, typename U> void fun1(const T&); fun0(0, foo{}); fun1<int, foo>(0); déduction automatique à partir des arguments tous les types sont présents dans les arguments
  • 201. Fonctions templates 143 struct foo{}; template <typename T, typename U> void fun0(const T&, const U&); template <typename T, typename U> void fun1(const T&); fun0(0, foo{}); fun1<int, foo>(0); déduction automatique à partir des arguments tous les types sont présents dans les arguments les types ne sont pas tous présents dans les arguments, il donc les expliciter
  • 202. Fonctions templates 144 template <typename T> struct foo { T x; }; template <typename T> foo<T> mk_foo(const T& x) { return {x}; } const auto f0 = foo<int>(42); const auto f1 = mk_foo(42); pratique pour “cacher” l’argument du template
  • 203. Fonctions templates 144 template <typename T> struct foo { T x; }; template <typename T> foo<T> mk_foo(const T& x) { return {x}; } const auto f0 = foo<int>(42); const auto f1 = mk_foo(42); pratique pour “cacher” l’argument du template pas de type explicite
  • 204. Fonctions templates 145 les fonctions membres peuvent être aussi génériques template <typename T> struct foo { T x_; foo(const T& x) : x_(x) {} template <typename U> void bar(const U&) {} }; auto f = foo<int>{42}; f.bar(3.22);
  • 205. Fonctions templates 145 les fonctions membres peuvent être aussi génériques template <typename T> struct foo { T x_; foo(const T& x) : x_(x) {} template <typename U> void bar(const U&) {} }; auto f = foo<int>{42}; f.bar(3.22);méthode générique
  • 206. Templates :“fabriques” 146 • Une structure template est une “fabrique de type” ‣ template <typename T> struct foo n’est pas un type - on ne peut pas créer d’objet de type foo<T> ‣ foo<int> est “généré” à partir de foo<T> - c’est un type, on peut créer un objet à partir de foo<int> • Une fonction template est une “fabrique de fonctions” ‣ on n’appelle pas directement template <typename T> foo()
  • 207. Accès à un type imbriqué 147 struct bar { typedef int value_type; }; void foo(const bar&) { bar::value_type x; } dans un contexte non-générique
  • 208. Accès à un type imbriqué 147 struct bar { typedef int value_type; }; void foo(const bar&) { bar::value_type x; } dans un contexte non-générique OK
  • 209. Accès à un type imbriqué 148 struct bar { typedef int value_type; }; template <typename T> void foo(const T&) { T::value_type x; } error: missing 'typename' prior to dependent type name 'T::value_type'   T::value_type x;   ^~~~~~~~~~~~~   typename dans un contexte générique
  • 210. Accès à un type imbriqué 148 struct bar { typedef int value_type; }; template <typename T> void foo(const T&) { T::value_type x; } error: missing 'typename' prior to dependent type name 'T::value_type'   T::value_type x;   ^~~~~~~~~~~~~   typename ! dans un contexte générique
  • 211. Accès à un type imbriqué 149 struct bar { typedef int value_type; }; template <typename T> void foo(const T&) { typename T::value_type x; } dans un contexte générique
  • 212. Accès à un type imbriqué 149 struct bar { typedef int value_type; }; template <typename T> void foo(const T&) { typename T::value_type x; } dans un contexte générique OK
  • 213. 150 Dependant templates struct bar { template <typename U> U get() const {} }; template <typename T> void foo(const T& b) { const auto x = b.get<int>(); } auto b = bar{}; foo(b); error: use 'template' keyword to treat 'get' as a dependent template name   const auto x = b.get<T>();                    ^                    template
  • 214. 150 Dependant templates struct bar { template <typename U> U get() const {} }; template <typename T> void foo(const T& b) { const auto x = b.get<int>(); } auto b = bar{}; foo(b); error: use 'template' keyword to treat 'get' as a dependent template name   const auto x = b.get<T>();                    ^                    template !
  • 215. 151 Dependant templates struct bar { template <typename U> U get() const {} }; template <typename T> void foo(const T& b) { const auto x = b.template get<int>(); }
  • 216. 151 Dependant templates struct bar { template <typename U> U get() const {} }; template <typename T> void foo(const T& b) { const auto x = b.template get<int>(); } OK
  • 217. 151 Dependant templates struct bar { template <typename U> U get() const {} }; template <typename T> void foo(const T& b) { const auto x = b.template get<int>(); } OK get est une fonction template qui dépend du type T qui est lui même un paramètre template
  • 218. alias 152 // the old way typedef int my_typedef; // aliases using my_alias = int; using : successeur de typedef
  • 219. alias 152 // the old way typedef int my_typedef; // aliases using my_alias = int; lecture homogène avec auto var = …; using : successeur de typedef
  • 220. alias 153 template <typename T, typename U> struct foo{}; template <typename T> struct templated_typedef { typedef foo<T, int> type; }; int main() { const auto f = templated_typedef<int>::type{}; } essayons tout de même (1) impossible d’avoir des typedef template
  • 221. alias 154 template <typename T, typename U> struct foo{}; template <typename T> struct templated_typedef { typedef foo<T, int> type; }; template <typename T> void bar(const typename templated_typedef<T>::type&); int main() { const auto f = templated_typedef<int>::type{}; bar(f); } impossible d’avoir des typedef template essayons tout de même (2)
  • 222. alias 154 template <typename T, typename U> struct foo{}; template <typename T> struct templated_typedef { typedef foo<T, int> type; }; template <typename T> void bar(const typename templated_typedef<T>::type&); int main() { const auto f = templated_typedef<int>::type{}; bar(f); } note: candidate template ignored: couldn't infer template argument 'T' void bar(const typename templated_typedef<T>::type&); impossible d’avoir des typedef template essayons tout de même (2) !
  • 223. alias 155 template <typename T, typename U> struct foo{}; template <typename T> using alias_t = foo<T, int>; int main() { const auto f0 = foo<double, int>{}; const auto f1 = alias_t<int>{}; } alias templates
  • 224. Règles de déductions 156 template <typename T> void f(ParamType param); f(expression); deux types à déduire template <typename T> void f(const T& param); int x = 42; f(x); pseudo-code :
  • 225. Règles de déductions 156 template <typename T> void f(ParamType param); f(expression); type deT deux types à déduire template <typename T> void f(const T& param); int x = 42; f(x); pseudo-code :
  • 226. Règles de déductions 156 template <typename T> void f(ParamType param); f(expression); type deT deux types à déduire type de param template <typename T> void f(const T& param); int x = 42; f(x); pseudo-code :
  • 227. Règles de déductions 156 template <typename T> void f(ParamType param); f(expression); type deT deux types à déduire type de param template <typename T> void f(const T& param); int x = 42; f(x); int pseudo-code :
  • 228. Règles de déductions 156 template <typename T> void f(ParamType param); f(expression); type deT deux types à déduire type de param template <typename T> void f(const T& param); int x = 42; f(x); int const int& pseudo-code :
  • 229. Règles de déductions • Trois cas, le type de param ‣ est un pointeur ou une référence ‣ n’est ni un pointeur ni une référence ‣ est une référence universelle 157 template <typename T> void f(ParamType param);
  • 230. Règles de déductions 158 ParamType : pointeur ou référence (1) template <typename T> void f(T& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int int& f(cx) const int const int& f(rx) const int const int&
  • 231. Règles de déductions 158 ParamType : pointeur ou référence (1) template <typename T> void f(T& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int int& f(cx) const int const int& f(rx) const int const int& idem pour les pointeurs
  • 232. Règles de déductions 159 ParamType : pointeur ou référence (2) template <typename T> void f(const T& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int const int& f(cx) const int const int& f(rx) const int const int&
  • 233. Règles de déductions 159 ParamType : pointeur ou référence (2) template <typename T> void f(const T& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int const int& f(cx) const int const int& f(rx) const int const int& idem pour les pointeurs
  • 234. Règles de déductions 160 ParamType : ni pointeur, ni référence template <typename T> void f(T param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int int f(cx) int int f(rx) int int
  • 235. Règles de déductions 160 ParamType : ni pointeur, ni référence template <typename T> void f(T param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int int f(cx) int int f(rx) int int par valeur
  • 236. Règles de déductions 160 ParamType : ni pointeur, ni référence template <typename T> void f(T param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int int f(cx) int int f(rx) int int par valeur copie : const est ignoré
  • 237. Règles de déductions 161 ParamType : rvalue reference template <typename T> void f(T&& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int& int& f(cx) const int& const int& f(rx) const int& const int& f(42) int int&& lvalues rvalues
  • 238. Règles de déductions 161 ParamType : rvalue reference template <typename T> void f(T&& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int& int& f(cx) const int& const int& f(rx) const int& const int& f(42) int int&& idem pour les pointeurs lvalues rvalues
  • 239. Règles de déductions 161 ParamType : rvalue reference template <typename T> void f(T&& param); int x = 2; const int cx = x; const int& rx = x; T param f(x) int& int& f(cx) const int& const int& f(rx) const int& const int& f(42) int int&& idem pour les pointeurs lvalues rvalues “référence universelle”
  • 240. 162 template <typename T> void print_type() { std::cout << __PRETTY_FUNCTION__; } Afficher le type déduit void print_type() [T = foo] (GCC, clang)
  • 241. 163 template <typename T> void print_type() { std::cout << __FUNCSIG__; } void _cdecl print_type<struct foo>(void) (Visual Studio 2013) Afficher le type déduit
  • 242. 164 template <typename T> struct print_type; print_type<foo>{}; (tous compilateurs) Afficher le type déduit error: implicit instantiation of undefined template 'print_type<foo>'   print_type<foo>{};   ^
  • 243. 164 template <typename T> struct print_type; print_type<foo>{}; (tous compilateurs) Afficher le type déduit ne pas donner de définition error: implicit instantiation of undefined template 'print_type<foo>'   print_type<foo>{};   ^
  • 244. Spécialisation 165 scénario : un algorithme peut-être optimisé pour un type particulier struct foo{}; template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <> struct algo<foo> { void operator()() {std::cout << "O(1)";} }; algo<foo>{}(); // “O(1)” algo<int>{}(); // “O(n)”
  • 245. Spécialisation 165 scénario : un algorithme peut-être optimisé pour un type particulier struct foo{}; template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <> struct algo<foo> { void operator()() {std::cout << "O(1)";} }; algo<foo>{}(); // “O(1)” algo<int>{}(); // “O(n)” générique
  • 246. Spécialisation 165 scénario : un algorithme peut-être optimisé pour un type particulier struct foo{}; template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <> struct algo<foo> { void operator()() {std::cout << "O(1)";} }; algo<foo>{}(); // “O(1)” algo<int>{}(); // “O(n)” spécialisation générique
  • 247. Spécialisation 166 fonctions struct foo{}; template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } algo(foo{}); // “O(1)” algo(42); // “O(n)”
  • 248. Spécialisation 166 fonctions struct foo{}; template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } algo(foo{}); // “O(1)” algo(42); // “O(n)” générique
  • 249. Spécialisation 166 fonctions struct foo{}; template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } algo(foo{}); // “O(1)” algo(42); // “O(n)” spécialisation générique
  • 250. Spécialisation 167 fonctions, une petite surprise… template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } void algo(const foo&) { std::cout << "O(1) bis"; } algo(foo{}); // “O(1) bis” algo(42); // “O(n)”
  • 251. Spécialisation 167 fonctions, une petite surprise… template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } void algo(const foo&) { std::cout << "O(1) bis"; } algo(foo{}); // “O(1) bis” algo(42); // “O(n)” spécialisation générique surcharge
  • 252. Spécialisation 167 fonctions, une petite surprise… template <typename T> void algo(const T&) { std::cout << "O(n)"; } template <> void algo(const foo&) { std::cout << "O(1)"; } void algo(const foo&) { std::cout << "O(1) bis"; } algo(foo{}); // “O(1) bis” algo(42); // “O(n)” spécialisation générique surcharge préférer les surcharges aux spécialisations
  • 253. Spécialisation partielle 168 scénario : un algorithme peut-être optimisé pour un conteneur générique particulier template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)”
  • 254. Spécialisation partielle 168 scénario : un algorithme peut-être optimisé pour un conteneur générique particulier template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” générique
  • 255. Spécialisation partielle 168 scénario : un algorithme peut-être optimisé pour un conteneur générique particulier template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” générique spécialisation partielle
  • 256. Spécialisation partielle 169 on peut garder des spécialisations totales template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; template <> struct algo<std::vector<double>> { void operator()() {std::cout << "O(1) double";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” algo<std::vector<double>>{}(); // “O(1) double”
  • 257. Spécialisation partielle 169 on peut garder des spécialisations totales template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; template <> struct algo<std::vector<double>> { void operator()() {std::cout << "O(1) double";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” algo<std::vector<double>>{}(); // “O(1) double” générique
  • 258. Spécialisation partielle 169 on peut garder des spécialisations totales template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; template <> struct algo<std::vector<double>> { void operator()() {std::cout << "O(1) double";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” algo<std::vector<double>>{}(); // “O(1) double” générique spécialisation partielle
  • 259. Spécialisation partielle 169 on peut garder des spécialisations totales template <typename T> struct algo { void operator()() {std::cout << "O(n)";} }; template <typename T> struct algo<std::vector<T>> { void operator()() {std::cout << "O(1)";} }; template <> struct algo<std::vector<double>> { void operator()() {std::cout << "O(1) double";} }; algo<int>{}(); // “O(n)” algo<std::vector<int>>{}(); // “O(1)” algo<std::vector<double>>{}(); // “O(1) double” générique spécialisation partielle spécialisation totale
  • 260. Template-template arguments 170 template <typename T> struct vector {}; template <typename T, template <typename DUMMY> class Container> struct foo { Container<T> cont_; }; foo<int, vector>{}; prendre en paramètre template un template (1)
  • 261. Template-template arguments 170 template <typename T> struct vector {}; template <typename T, template <typename DUMMY> class Container> struct foo { Container<T> cont_; }; foo<int, vector>{}; obligatoire prendre en paramètre template un template (1)
  • 262. Template-template arguments 170 template <typename T> struct vector {}; template <typename T, template <typename DUMMY> class Container> struct foo { Container<T> cont_; }; foo<int, vector>{}; obligatoire nom sans importance peut être omis prendre en paramètre template un template (1)
  • 263. Template-template arguments 170 template <typename T> struct vector {}; template <typename T, template <typename DUMMY> class Container> struct foo { Container<T> cont_; }; foo<int, vector>{}; obligatoire nom sans importance peut être omis T est passé à Container prendre en paramètre template un template (1)
  • 264. Template-template arguments 171 template <typename T, template <typename> class Container> struct foo { Container<T> cont_; }; foo<int, std::vector>{}; prendre en paramètre template un template (2) error: template template argument has different template parameters than its corresponding template template parameter   foo<int, std::vector>{};                 ^ note: too many template parameters in template template argument template <class _Tp, class _Allocator = allocator<_Tp> > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attention aux nombres de paramètres…
  • 265. Template-template arguments 171 template <typename T, template <typename> class Container> struct foo { Container<T> cont_; }; foo<int, std::vector>{}; prendre en paramètre template un template (2) ! error: template template argument has different template parameters than its corresponding template template parameter   foo<int, std::vector>{};                 ^ note: too many template parameters in template template argument template <class _Tp, class _Allocator = allocator<_Tp> > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attention aux nombres de paramètres…
  • 266. Valeurs en paramètres template 172 template <int Value> struct foo { void operator()() const { std::cout << Value; } }; foo<42>{}(); on peut utiliser des valeurs comme paramètres template template <bool Value> struct foo { void operator()() const { std::cout << Value; } }; foo<true>{}();
  • 267. Valeurs en paramètres template 173 expressions constantes seulement template <int Value> struct foo; const auto i = 42; auto j = i; foo<i>{}(); // OK foo<j>{}(); // ERROR error: non-type template argument is not a constant expression   foo<j>{}(); // ERROR       ^ note: read of non-const variable 'j' is not allowed in a constant expression
  • 268. Valeurs en paramètres template 173 expressions constantes seulement template <int Value> struct foo; const auto i = 42; auto j = i; foo<i>{}(); // OK foo<j>{}(); // ERROR ! error: non-type template argument is not a constant expression   foo<j>{}(); // ERROR       ^ note: read of non-const variable 'j' is not allowed in a constant expression
  • 269. Valeurs en paramètres template 174 la spécialisation fonctionne aussi template <int Value> struct fact { static const auto value = Value * fact<Value - 1>::value; }; template <> struct fact<0> { static const auto value = 1; }; std::cout << fact<5>::value; // 120
  • 270. Valeurs en paramètres template 174 la spécialisation fonctionne aussi template <int Value> struct fact { static const auto value = Value * fact<Value - 1>::value; }; template <> struct fact<0> { static const auto value = 1; }; std::cout << fact<5>::value; // 120 récursion : cas général récursion : cas de base
  • 271. Curiously RecurringTemplate Pattern (CRTP) 175 template <typename T> struct foo {}; struct bar : public foo<bar> {}; classe héritée générique
  • 272. Variadic templates 176 template<typename T> T add(T x) { return x; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } add(1,2); // 3 add(1,2,3); // 6 add(1,2,3,4); // 10 // etc. nombre variable de paramètres template
  • 273. Variadic templates 176 template<typename T> T add(T x) { return x; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } add(1,2); // 3 add(1,2,3); // 6 add(1,2,3,4); // 10 // etc. nombre variable de paramètres template “parameter pack”
  • 274. Variadic templates 176 template<typename T> T add(T x) { return x; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } add(1,2); // 3 add(1,2,3); // 6 add(1,2,3,4); // 10 // etc. nombre variable de paramètres template expansion du pack “parameter pack”
  • 275. Variadic templates 177 int add(int arg1) { return arg1; } int add(int arg1, int arg2) { return arg1 + add(arg2); } int add(int arg1, int arg2, int arg3) { return arg1 + add(arg2, arg3); } add(1,2,3); // 6 code “déroulé” template<typename T> T add(T x) { return x; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); }
  • 276. Variadic templates 178 raisonnement programmation fonctionnelle pure template<typename T> T add(T x) { return v; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } “déconstruction" de la liste de types head::tail Caml, Standard ML, Haskell, Scala, etc.
  • 277. Variadic templates 178 raisonnement programmation fonctionnelle pure template<typename T> T add(T x) { return v; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } head “déconstruction" de la liste de types head::tail Caml, Standard ML, Haskell, Scala, etc.
  • 278. Variadic templates 178 raisonnement programmation fonctionnelle pure template<typename T> T add(T x) { return v; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } head tail “déconstruction" de la liste de types head::tail Caml, Standard ML, Haskell, Scala, etc.
  • 279. Variadic templates 178 raisonnement programmation fonctionnelle pure template<typename T> T add(T x) { return v; } template<typename T, typename... Ts> T add(T x, Ts... xs) { return x + add(xs...); } head tail “déconstruction" de la liste de types head::tail Caml, Standard ML, Haskell, Scala, etc. head
  • 280. Variadic templates 179 template<typename T> T add(T v) { return v; } template<typename T, typename... Args> T add(T first, Args... args) { return first + add(args...); } std::string operator ""_s(const char *str, std::size_t) { return {str}; } add(“1”_s,"2"_s,"3"_s); // “123” pour le plaisir…
  • 281. Variadic templates 180 // Signature of a meta-function that add integers template <int... Xs> struct add; template <int X, int... Xs> struct add<X, Xs...> { static const auto value = X + add<Xs...>::value; }; template <int X> struct add<X> { static const auto value = X ; }; add<1,2,3>::value; // 6 les struct/class aussi
  • 282. Variadic templates 181 connaître la taille d’un pack avec sizeof... template <typename... Ts> std::size_t foo() { return sizeof...(Ts); } std::cout << foo<int, double, char>(); // 3
  • 283. Variadic templates 182 expansion d’un pack (1) template <typename... Ts> struct foo{}; template<typename X, typename Y, typename... Z> void bar(X, Y, Z...) { print_type< foo<X, Y, Z...> >(); print_type< foo<X, Z..., Y> >(); print_type< foo<Z..., X, Y> >(); } bar(int{}, int{}, double{}, std::string{}); void print_type() [T = foo<int, int, double, std::__1::basic_string<char> >] void print_type() [T = foo<int, double, std::__1::basic_string<char>, int>] void print_type() [T = foo<double, std::__1::basic_string<char>, int, int>]
  • 284. Variadic templates 182 expansion d’un pack (1) template <typename... Ts> struct foo{}; template<typename X, typename Y, typename... Z> void bar(X, Y, Z...) { print_type< foo<X, Y, Z...> >(); print_type< foo<X, Z..., Y> >(); print_type< foo<Z..., X, Y> >(); } bar(int{}, int{}, double{}, std::string{}); void print_type() [T = foo<int, int, double, std::__1::basic_string<char> >] void print_type() [T = foo<int, double, std::__1::basic_string<char>, int>] void print_type() [T = foo<double, std::__1::basic_string<char>, int, int>] Z… en dernière position
  • 285. Variadic templates 183 expansion d’un pack (2) template<typename... Values> std::array<int, sizeof...(Values)> make_array(Values... values) { return std::array<int, sizeof...(Values)>{values...}; } const auto a = make_array(1,2,3); template<typename... Args> void foo(Args... values) { int tab[sizeof...(Args)] = {values...}; } foo(1,2,3);
  • 286. Variadic templates 184 expansion d’un pack : héritage struct base1 { void foo(){} }; struct base2 { void bar(){} }; template <typename... Bases> class derived : public Bases... {}; auto d = derived<base1, base2>{}; d.foo(); d.bar();
  • 287. Variadic templates 185 spécialisation template <typename... Ts> struct foo {}; template <typename... Ts> struct bar; template <typename... Ts> struct bar<foo<Ts...>> {}; using foo_type = foo<int, char>; using bar_type = bar<foo_type>;
  • 288. Variadic templates 185 spécialisation template <typename... Ts> struct foo {}; template <typename... Ts> struct bar; template <typename... Ts> struct bar<foo<Ts...>> {}; using foo_type = foo<int, char>; using bar_type = bar<foo_type>; permet d’accéder à liste de paramètres de foo
  • 289. Variadic templates 186 template <typename... Ts> struct tuple {}; template <typename T, typename... Ts> struct tuple<T, Ts...> : tuple<Ts...> { tuple(T t, Ts... ts) : tuple<Ts...>(ts...) , current(t) {} T current; }; structure récursive
  • 290. Références universelles 187 template <typename T> void f(T&& param); • Dénomination de Scott Meyers • En présence d’une déduction de type (templates) • Il faudrait parler de ‣ forwarding reference ‣ en cours de standardisation (la dénomination) ‣ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/ n4164.pdf
  • 291. Références universelles 187 template <typename T> void f(T&& param); • Dénomination de Scott Meyers • En présence d’une déduction de type (templates) • Il faudrait parler de ‣ forwarding reference ‣ en cours de standardisation (la dénomination) ‣ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/ n4164.pdf && sur paramètre template
  • 292. Perfect forwarding 188 le problème : passer des paramètres de manière transparente à une sous-fonction template <typename Fun, typename T> void logger(const T& x) { std::cout << "beforen"; Fun{}(x); std::cout << "aftern"; } template <typename Fun, typename T> void logger(T& x) { std::cout << "beforen"; Fun{}(x); std::cout << "aftern"; } et s’il y a plusieurs paramètres?…
  • 293. Perfect forwarding solution : std::forward template <typename Fun, typename Arg> void logger(Arg&& x) { std::cout << "beforen"; Fun{}(std::forward<Arg>(x)); std::cout << "aftern"; }
  • 294. Perfect forwarding 190 comment ça fonctionne? (1) A& & → A& A& && → A& A&& & → A& A&& && → A&& si invocation f(a) a de type A Arg x lvalue A& A& rvalue A&& A&& template<typename Arg> void f(Arg&& x); “collapsing rules” application des collapsing rules
  • 295. Perfect forwarding 191 comment ça fonctionne? (2) template<class T> T&& forward(typename remove_reference<T>::type& a) { return static_cast<T&&>(a); }
  • 296. Perfect forwarding 192 void logger(X& && x) { std::cout << "beforen"; Fun{}(std::forward<X&>(x)); std::cout << "aftern"; } X& && forward(typename remove_reference<X&>::type& a) { return static_cast<X& &&>(a); } void logger(X& x) { std::cout << "beforen"; Fun{}(std::forward<X&>(x)); std::cout << "aftern"; } X& forward(X& a) { return static_cast<X&>(a); } sur une lvalue
  • 297. Perfect forwarding 193 sur une rvalue void logger(X&& && x) { std::cout << "beforen"; Fun{}(std::forward<X&&>(x)); std::cout << "aftern"; } X&& && forward(typename remove_reference<X&&>::type& a) { return static_cast<X&& &&>(a); } void logger(X&& x) { std::cout << "beforen"; Fun{}(std::forward<X&&>(x)); std::cout << "aftern"; } X&& forward(X& a) { return static_cast<X&&>(a); }
  • 298. Perfect forwarding vs move 194 void foo(int&&) {std::cout << "int&&";} void foo(const int&) {std::cout << "const int&";} void foo(int&) {std::cout << "int&";} template <typename T> void apply(T&& x) { std::cout << "A"; foo(std::forward<T>(x));} } void apply(int&& x) { std::cout << "B"; foo(std::move(x)); } apply(i); apply(ri); apply(cri); apply(42); apply(std::move(i)); quel est l’affichage? auto i = 2; auto& ri = i; const auto& cri = i;
  • 300. 196 begin/end auto vec = std::vector<int>{1,2,3}; auto it = begin(vec); // vec.begin() *it = 42; auto cit = cbegin(vec); // vec.cbegin() *cit = 33; // error fonctions libres for (auto cit = cbegin(vec); cit != cend(vec); ++cit) { // ... }
  • 301. 197 begin/end tableaux C int tab[] = {1,2,3}; for (auto it = std::begin(tab); it != std::end(tab); ++it) { *it = 0; }
  • 302. 197 begin/end tableaux C int tab[] = {1,2,3}; for (auto it = std::begin(tab); it != std::end(tab); ++it) { *it = 0; } appel “fully qualified”
  • 303. 198 next/prev auto vec = std::vector<int>{1,2,3}; auto it = begin(vec); auto it1 = next(it); // return a copy incremented by 1 auto it2 = next(it, 2); // return a copy incremented by 2 auto it3 = prev(it2); // return a copy decremented by 1 auto it4 = prev(it3, 1); // return a copy decremented by 1
  • 304. 199 move déplacer un conteneur auto vec1 = std::vector<foo>{foo{}, foo{}}; auto vec2 = std::vector<foo>{}; std::cout << vec1.size(); std::cout << vec2.size(); std::move(begin(vec1), end(vec1), std::back_inserter(vec2)); std::cout << vec1.size(); std::cout << vec2.size();
  • 305. 200 all_of, any_of, any_of auto vec1 = std::vector<bool>{true, true, true}; auto vec2 = std::vector<bool>{true, false, true}; std::cout << std::boolalpha; std::cout << std::all_of( begin(vec1), end(vec1) , [](bool x){return x;}); std::cout << std::any_of( begin(vec2), end(vec2) , [](bool x){return not x;});
  • 306. 201 emplace, emplace_back construction en place grâce au perfect forwarding struct foo { foo(int) {std::cout << "foo(int)";} foo(const foo&) {std::cout << "foo(const foo&)";} foo& operator=(const foo&) {std::cout << "operator=(const foo&)"; return *this;} foo(foo&&) {std::cout << "foo(foo&&)";} foo& operator=(foo&&) {std::cout << "operator=(foo&&)"; return *this;} }; auto vec1 = std::vector<foo>{}; vec1.reserve(3); auto f = foo{1}; vec1.push_back(f); vec1.push_back(foo{2}); vec1.emplace_back(3);
  • 307. 202 shrink_to_fit deque, string et vector auto vec1 = std::vector<int>{}; std::cout << vec1.capacity(); vec1.push_back(1); vec1.push_back(1); vec1.push_back(1); std::cout << vec1.capacity(); vec1.shrink_to_fit(); std::cout << vec1.capacity(); peut libérer de la mémoire
  • 308. 203 forward_list liste simplement chaînée auto l = std::forward_list<int>{1,2,3}; std::cout << l.size(); // error, no size() member auto cit0 = begin(l); auto cit1 = next(cit0); auto cit2 = prev(cit1); // error, not bidirectional
  • 309. 204 array auto a1 = std::array<int, 3>{}; const auto cit = a1.cbegin(); const auto& x = a1[2]; // use like a C-array const auto& y = a1.at(10); // std::out_of_range auto a2 = std::array<int, 3>{}; if (a1 == a2) { // ... } auto a3 = a1; // etc. tableaux C pour le C++ strictement les mêmes performances! à privilégier dans tout nouveau code
  • 310. 205 array const auto a0 = std::array<int, 3>{1,2,3}; const auto a1 = a0; toutes les facilités du C++ (1) const int t0[3] = {1,2,3}; int t1[3]; std::copy(t0, t0 + 3, t1); vs copie
  • 311. 205 array const auto a0 = std::array<int, 3>{1,2,3}; const auto a1 = a0; toutes les facilités du C++ (1) dangereux const int t0[3] = {1,2,3}; int t1[3]; std::copy(t0, t0 + 3, t1); vs copie
  • 312. 206 array const auto a0 = std::array<int, 3>{1,2,3}; const auto res = std::find(begin(a0), end(a0), 3); if (res != end(a0)) { std::cout << "foundn"; } toutes les facilités du C++ (2) utilisation des algorithmes STL
  • 313. 207 array auto a0 = std::array<int, 3>{1, 2, 3}; auto a1 = std::array<int, 3>{1, 99, 3}; const auto res = memcmp(a0.data(), a1.data(), 3 * sizeof(int)); std::cout << res << 'n'; memcpy(a0.data(), a1.data(), 3 * sizeof(int)); for (auto x : a0) { std::cout << x << 'n'; } utilisation avec les fonctions C .data() pour accéder au tableau C
  • 314. 208 tuple conteneur de types hétérogène auto t1 = std::tuple<int, char, foo>{2, 'a', foo{}}; auto t2 = std::make_tuple(2, 'a', foo{}); const auto& f = std::get<2>(t2);
  • 315. 209 tuple permet de retourner plusieurs valeurs sans avoir à créer un nouveau type (1) struct foo {}; std::tuple<int, foo> bar() { return std::make_tuple(2, foo{}); } const auto t = bar();
  • 316. 210 tuple permet de retourner plusieurs valeurs sans avoir à créer un nouveau type (2) struct foo {}; std::tuple<int, foo> bar() { return std::make_tuple(2, foo{}); } auto i = 0; auto f = foo{}; std::tie(i, f) = bar(); std::cout << i; // 2
  • 317. 211 tuple concaténer des tuples auto t0 = std::make_tuple(1, foo{}, 'a'); std::cout << std::tuple_size<decltype(t0)>::value; // 3 auto t1 = std::make_tuple(3.14, std::string{"abc"}); std::cout << std::tuple_size<decltype(t1)>::value; // 2 auto t2 = std::tuple_cat(t0, t1); std::cout << std::tuple_size<decltype(t2)>::value; // 5
  • 318. 212 unordered_map table de hachage auto map = std::unordered_map<int, std::string>{}; map.insert({42, "abc"}); map.emplace(33, "def"); for (const auto& key_value : map) { std::cout << key_value.first << " -> " << key_value.second; } fonctionne comme std::map
  • 319. 213 unordered_map fonctions spécifiques aux tables de hachage auto map = std::unordered_map<int, std::string>{1'000'000}; peut-être initialisée avec un nombre de buckets map.rehash(2'000'000); peut-être redimensionnée map.load_factor() afficher le facteur de charge
  • 320. 214 unordered_map utiliser un type personnalisé en tant que clé namespace std { template <> struct hash<foo> { std::size_t operator()(const foo& f) const { // hash function } }; } bool operator==(const foo&, const foo&); struct foo { // some data }; clé égalité hachage
  • 321. 214 unordered_map utiliser un type personnalisé en tant que clé namespace std { template <> struct hash<foo> { std::size_t operator()(const foo& f) const { // hash function } }; } bool operator==(const foo&, const foo&); struct foo { // some data }; clé égalité hachage spécialisation
  • 322. 215 unordered_map bonus: combiner des valeurs de hachage (1) /// @brief Combine the hash value of x with seed. /// /// Taken from <boost/functional/hash.hpp>. /// Sligthy modified to use std::hash<T> instead of /// boost::hash_value(). template <typename T> inline void hash_combine(std::size_t& seed, const T& x) noexcept(noexcept(std::hash<T>()(x))) { seed ^= std::hash<T>()(x) + 0x9e3779b9 + (seed<<6) + (seed>>2); }
  • 323. 216 unordered_map bonus: combiner des valeurs de hachage (2) namespace std { template <> struct hash<foo> { std::size_t operator()(const foo& f) const { auto seed = 0ul; hash_combine(seed, f.x); hash_combine(seed, f.y); return seed; } }; }
  • 324. 217 Gestion de la mémoire • introduction de unique_ptr ‣ auto_ptr deprecated ‣ utilise les portées pour désallouer • introduction de shared_ptr ‣ déjà présent dans Boost et POCCO ‣ comptage de référence • désallocation automatique dans tous les cas