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 seman...
4
ranged-base for loop
auto
constexpr
static_assert
rvalues references
enum class
uniform initialization
noexcept
variadic...
5
shared_ptr
unordered_map
mutex
thread
atomic
regex
unique_ptr
bind
reference_wrapper
unordered_set
tuple
chrono
random
f...
Compilateurs
6
• Visual Studio 2013 (incomplet)
‣ http://msdn.microsoft.com/en-us/library/hh567368.aspx
‣ plus gros manque...
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)...
Boucles simplifiées
10
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2...
Boucles simplifiées
10
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2...
Boucles simplifiées
11
{
typedef std::vector<int>::const_iterator cit_t;
for ( cit_t __begin = v.begin(), __end = v.end()
;...
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 :...
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 :...
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 membr...
auto
15
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<int, int>& key_val...
auto
16
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<const int, int>& k...
auto
16
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1,1));
for (std::pair<const int, int>& k...
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)
{
// .....
18
auto
#include <map>
int main()
{
auto m = std::map<int, int>();
m.insert(std::make_pair(1,1));
for (auto& key_value : m...
18
auto
#include <map>
int main()
{
auto m = std::map<int, int>();
m.insert(std::make_pair(1,1));
for (auto& key_value : m...
19
auto m = std::map<int, int>();
for (const auto& key_value : m)
{
key_value.second = 2; // compilation error
}
auto
auto...
20
#include <vector>
std::vector<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const ...
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const au...
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const au...
21
#include <deque>
std::deque<int> fun()
{
// return something
}
int main()
{
const auto container = fun();
for (const au...
22
• permet d’adopter un style de programmation fonctionnelle
‣ Scala : val x = fun()
‣ C++ : const auto x = fun();
• auto...
23
const auto x = foo();
void* _ = x;
error: cannot initialize a variable of type 'void *' with an lvalue of type
'TYPE'
 ...
Initialisation uniformisée
24
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// function declaration or variable d...
25
Initialisation uniformisée
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// add parentheses to declare a varia...
26
struct foo {};
struct bar
{
bar(foo){}
};
int main()
{
// brace initializer
bar b{foo{}};
// better
auto b1 = bar{foo{}...
27
struct foo
{
int i_;
foo(int i) : i_(i) {}
};
struct bar
{
int i_;
};
int main()
{
const auto f = foo{42};
const auto b...
28
class foo
{
int i_;
public:
foo(int i) : i_(i) {}
};
struct bar
{
int i_;
};
int main()
{
const auto f = foo{42};
const...
29
struct foo
{
int i;
};
foo fun()
{
return {42};
}
int main()
{
const auto f = fun();
}
concision : on peut omettre le t...
29
struct foo
{
int i;
};
foo fun()
{
return {42};
}
int main()
{
const auto f = fun();
}
concision : on peut omettre le t...
30
#include <map>
int main()
{
auto m = std::map<int,int>{};
// old style
m.insert(std::make_pair(1, 2));
// new style
m.i...
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...
32
• Que choisir?
• “{}”
‣ résistant au most vexing parse
‣ empêche la perte de précision
‣ utilisation plus cohérente
• “...
initializer_list
33
#include <iostream>
#include <vector>
int main()
{
const auto vec = std::vector<int>{1,2,3};
for (cons...
initializer_list
33
#include <iostream>
#include <vector>
int main()
{
const auto vec = std::vector<int>{1,2,3};
for (cons...
initializer_list
34
• C++11 définit un nouveau type
‣ std::initializer_list<T>
‣ #include <initializer_list>
• Utilise la m...
initializer_list
35
#include <initializer_list>
int main()
{
// deduced to std::initializer_list<int>
const auto list = {1...
initializer_list
35
#include <initializer_list>
int main()
{
// deduced to std::initializer_list<int>
const auto list = {1...
initializer_list
36
void foo(std::initializer_list<int> list)
{
for (auto i : list) {}
}
foo({1,2,3});
initializer_list en...
initializer_list
36
void foo(std::initializer_list<int> list)
{
for (auto i : list) {}
}
foo({1,2,3});
passage par valeur
...
initializer_list
37
struct bar
{
bar(std::initializer_list<int> list);
};
const auto b = bar{1,2,3};
can be used to constr...
initializer_list
38
void foo(int i, std::initializer_list<int> li)
{
std::cout << i << " : ";
for (auto x : li) std::cout ...
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:...
initializer_list
41
#include <iostream>
#include <vector>
int main ()
{
const auto v1 = std::vector<int>{2};
std::cout << ...
initializer_list
42
• Permet de
‣ faciliter l’écriture des tests unitaires
‣ offrir une API élégante au code client
‣ …
co...
initializer_list
42
• Permet de
‣ faciliter l’écriture des tests unitaires
‣ offrir une API élégante au code client
‣ …
co...
User-defined literals
43
unsigned long x0 = 0ul;
long x1 = 0l;
// etc.
C++03 : il est possible de suffixer un littéral
pour ...
User-defined literals
44
long double
operator"" _deg (long double x)
{
return x * 3.141592/180;
}
const auto x = 90.0_deg;
...
User-defined literals
44
long double
operator"" _deg (long double x)
{
return x * 3.141592/180;
}
const auto x = 90.0_deg;
...
User-defined literals
45
struct foo
{
const unsigned long long x_;
foo(unsigned long long x)
: x_(x)
{}
};
foo
operator"" _...
User-defined literals
46
void
operator"" _print(const char* str, std::size_t)
{
std::cout << str;
}
"C++11 rocks!"_print;
à...
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 operato...
String literals
49
const auto utf8 = u8"UTF-8 string. u2705n”;
std::cout << utf8;
const auto utf16 = u8"UTF-16 string.n”;
...
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 = 0...
Raw string literals
52
const auto raw = R"(@
tLook Ma, no tabs!
some
text
)";
const auto escaped = "@n"
"somen"
"textn";
i...
enum class
53
int main()
{
enum e{pink, white, orange, brown};
const auto white = 0ul;
}
error: redefinition of 'white' as...
enum class
53
int main()
{
enum e{pink, white, orange, brown};
const auto white = 0ul;
}
ne compile pas
error: redefinitio...
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 dangereus...
enum class
55
int main()
{
enum class e{pink, white, orange, brown};
const auto white = 0ul;
const auto e0 = e::white;
}
e...
enum class
55
int main()
{
enum class e{pink, white, orange, brown};
const auto white = 0ul;
const auto e0 = e::white;
}
e...
enum class
56
enum class e{pink, white, orange, brown};
// use std::underlying_type<e>::type to find enum’s type
type par ...
enum class
57
enum class e : unsigned long
{pink = 0, white, orange, brown = 0xFFFFFFFFFFFFFFFF};
// use std::underlying_t...
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 header...
nullptr
59
void f(int) {std::cout << "f(int)";}
void f(void*){std::cout << "f(void*)";}
f(0);
f(NULL);
error: call to 'f' ...
nullptr
60
void f(int) {std::cout << "f(int)";}
void f(void*){std::cout << "f(void*)";}
f(0);
f(nullptr);
f(int)
f(void*)
...
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 i...
nullptr
62
type de nullptr
void f(int) {std::cout << "f(int)";}
void f(void*) {std::cout << "f(void*)";}
void f(std::nullp...
alignas
63
alignas(16) int a;
alignas(32768) int b;
std::cout << &a;
std::cout << &b;
0x7fff58d2ffe0
0x7fff58d28000
contrô...
alignof
64
std::cout << alignof(int);
std::cout << alignof(long);
std::cout << alignof(char);
std::cout << alignof(char*);...
Classes
• Délégation de constructeurs
• Héritage des constructeurs des classes de base
• Initialisation directe des attrib...
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égati...
Classes
67
délégation de constructeurs (2)
struct foo
{
const int x_;
foo(int x = 42)
: x_{x}
{}
};
on pourrait utiliser l...
Classes
68
héritage des constructeurs (1) : C++03
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : publi...
Classes
68
héritage des constructeurs (1) : C++03
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : publi...
Classes
69
héritage des constructeurs (2) : C++11
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : publi...
Classes
69
héritage des constructeurs (2) : C++11
struct base
{
const int x_;
base(int x)
: x_(x)
{}
};
struct foo : publi...
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 p...
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...
Classes
72
contrôle de l’héritage avec override (1)
struct base
{
virtual void operator()(float x) const
{std::cout << "ba...
Classes
72
contrôle de l’héritage avec override (1)
struct base
{
virtual void operator()(float x) const
{std::cout << "ba...
Classes
73
contrôle de l’héritage avec override (2)
struct base
{
virtual void operator()(float x) const;
};
struct derive...
Classes
73
contrôle de l’héritage avec override (2)
struct base
{
virtual void operator()(float x) const;
};
struct derive...
Classes
74
contrôle des fonctions membres avec default / delete (1)
struct non_copyable
{
non_copyable(){}
private:
non_co...
Classes
75
struct non_copyable
{
non_copyable() = default;
non_copyable(const non_copyable&) = delete;
non_copyable& opera...
Classes
76
struct base
{
virtual void operator()(int x) const;
};
struct derived : public base
{
virtual void operator()(i...
Classes
76
struct base
{
virtual void operator()(int x) const;
};
struct derived : public base
{
virtual void operator()(i...
delete
77
void foo(int){};
void foo(long) = delete;
void foo(double) = delete;
foo(42); // OK
foo(42l); // ERROR
foo(42.0)...
Rvalues references
• Ajout majeur au C++
• Travailler explicitement avec les temporaires
• Éviter des copies inutiles
‣ mo...
Rvalues references
• lvalues
‣ un objet qui occupe une place identifiable en mémoire
- qui a une adresse
• rvalues
‣ un obj...
Rvalues references
80
int foo() {return 2;}
int main()
{
foo() = 2;
}
error: lvalue required as left operand of assignment...
Rvalues references
81
struct foo {
foo() {
std::cout << “foo()n”;
}
foo(const foo&) {
std::cout << "foo(const foo&)n”;
}
f...
Rvalues references
81
struct foo {
foo() {
std::cout << “foo()n”;
}
foo(const foo&) {
std::cout << "foo(const foo&)n”;
}
f...
Rvalues references
82
comment éviter la copie? (1)
foo* bar() {return new foo{};}
auto f1 = bar();
// later...
f1 = bar();...
Rvalues references
83
comment éviter la copie? (2)
void bar(foo*);
auto f = foo{};
bar(&f);
• Passage par pointeur ou réfé...
Rvalues references
84
comment modifier un temporaire?
void bar(foo&);
//...
auto f = foo{};
bar(f1);
bar(foo{});
utile pour...
Rvalues references
84
comment modifier un temporaire?
void bar(foo&);
//...
auto f = foo{};
bar(f1);
bar(foo{}); ne compile...
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&& : rvalu...
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalu...
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalu...
Rvalues references
85
struct foo{int x;};
void bar(foo&& f)
{
std::cout << f.x << 'n';
}
//...
bar(foo{42});
foo&& : rvalu...
Rvalues references
86
une rvalue reference n’accepte que des rvalue expressions
struct foo{int x;};
void bar(foo&& f)
{
st...
Rvalues references
86
une rvalue reference n’accepte que des rvalue expressions
struct foo{int x;};
void bar(foo&& f)
{
st...
Rvalues references
87
ref-qualifiers
struct foo
{
void operator()() const
&&
{
std::cout << "&&n";
}
void operator()() cons...
Rvalues references
87
ref-qualifiers
struct foo
{
void operator()() const
&&
{
std::cout << "&&n";
}
void operator()() cons...
Move semantics
• Permet d’exprimer le “déplacement” d’une ressource
• Permet d’exprimer le changement de propriétaire d’un...
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 ...
Move semantics
90
struct foo {
some_type* ressource;
foo& operator=(const foo& rhs) {
// destroy this->ressource
// clone ...
Move semantics
91
auto f1 = foo{};
//...
auto f2 = std::move(f1);
// now f1 is “invalid”
transfert de ressource (1)
move()...
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.re...
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.re...
Move semantics
92
struct foo {
some_type* ressource;
foo& operator=(foo&& rhs) {
// destroy this->ressource
// copy rhs.re...
Move semantics
93
struct foo
{
foo() = default;
foo(const foo&) = default;
foo(foo&&) = delete;
};
int main()
{
const auto...
Move semantics
93
struct foo
{
foo() = default;
foo(const foo&) = default;
foo(foo&&) = delete;
};
int main()
{
const auto...
Move semantics
94
struct foo {};
foo return_by_value()
{
const auto f = foo{};
return f;
}
void take_by_value(foo) {}
auto...
Move semantics
95
transfert de propriété
struct foo
{
some_type ressource;
// forbid copy
foo(const foo&) = delete;
foo& o...
Move semantics
96
struct foo;
foo bar()
{
auto f = foo{};
// later...
return std::move(f);
}
std::move en retour d’une fon...
Move semantics
96
struct foo;
foo bar()
{
auto f = foo{};
// later...
return std::move(f);
}
mauvaise idée
std::move en re...
Move semantics
97
const rvalue references?
void bar(const foo&& f); // what for if we can't move f?
void bar(const foo&); ...
Move semantics
98
struct foo;
foo f1;
foo f2;
std::swap(f1, f2);
C++03 vs C++11
foo()
foo()
foo(foo&&)
operator=(foo&&)
op...
decltype
99
permet de connaître le type d’une expression
int* foo();
using ty0 = decltype(foo);
print_type<ty0>();
using t...
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 typ...
trailing return type
102
double (*get_fun2(bool arg))(double)
{
if (arg) return std::cos;
else return std::sin;
}
plus de ...
trailing return type
103
C++14 : on peut se passer du type de retour
template <typename T1, typename T2>
auto
add(const T1...
trailing return type
104
C++14 : on peut se passer du type de retour
mais pas toujours…
auto get_fun(bool arg)
{
if (arg) ...
105
lambdas
struct print1
{
void operator()(int x) const
{
std::cout << x << 'n';
}
};
void print2(int x)
{
std::cout << x...
lambdas
106
const auto v = {1,2,3};
std::for_each( begin(v), end(v)
, [](int x){std::cout << x << ‘n';}
);
const auto v = ...
lambdas
107
const auto print = [](int x){std::cout << x;};
print_type<decltype(print)>();
void print_type() [with T = cons...
lambdas
108
anatomie d’un lambda
[capture](params) -> ret_type {body}
comment “capturer”
l’environnement corps de la fonct...
lambdas
109
spécification du type de retour (1)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
cons...
lambdas
110
spécification du type de retour (2)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
cons...
lambdas
110
spécification du type de retour (2)
struct foo {};
struct bar : public foo {};
struct baz : public foo {};
cons...
lambdas
111
capture de l’environnement (1)
[] ne capture rien
[&] tout par référence
[=] tout par valeur
[this] capture th...
lambdas
111
capture de l’environnement (1)
[] ne capture rien
[&] tout par référence
[=] tout par valeur
[this] capture th...
struct foo
{
int x_;
int bar(int y)
{
return [this](int y)
{return x_ + y;}
(y);
}
};
std::cout << foo{40}.bar(2);
lambdas...
struct foo
{
int x_;
int bar(int y)
{
return [this](int y)
{return x_ + y;}
(y);
}
};
std::cout << foo{40}.bar(2);
lambdas...
auto x = 44u;
[=]{x -= 2;}();
lambdas
113
error: cannot assign to a variable captured by copy in a non-mutable lambda
  [=...
auto x = 44u;
[=]{x -= 2;}();
lambdas
113
error: cannot assign to a variable captured by copy in a non-mutable lambda
  [=...
lambdas
114
“fermeture” équivalente à un objet fonction (1)
struct closure
{
double& capture_;
int operator()(int x, int& ...
lambdas
114
“fermeture” équivalente à un objet fonction (1)
struct closure
{
double& capture_;
int operator()(int x, int& ...
lambdas
115
auto d = 0.0;
auto fun1 = fun0; // OK
fun1 = fun0; // KO no copy operator
using ty = decltype(fun0);
auto fun2...
lambdas
116
en paramètre d’un template
template <typename F, typename T>
void apply(T x)
{
F{}(x);
}
auto fun = [](int x){...
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int&...
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int&...
lambdas
117
attention aux références invalides
auto mk_fun()
-> std::function<void (int&)>
{
auto i = 33u;
return [&](int&...
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(...
lambdas
119
au service de l’immutabilité
const auto read_only = [&]
{
std::vector<int> res;
// super-complex initialisatio...
noexcept
• C++03
‣ il faut lister dans la signature d’une fonction les exceptions qu’elle
peut lever (throw (…))
‣ difficil...
noexcept
121
void foo()
noexcept
{
// shall not throw any exception
}
struct foo
{
void
operator()() const
noexcept
{
// s...
noexcept
122
opportunités d’optimisation
auto vec = std::vector<foo>{};
const auto f = foo{};
vec.push_back(f);
• Si vec d...
noexcept
123
noexcept conditionnel (1)
void bar()
noexcept
{
// shall not throw any exception
}
void foo()
noexcept(noexce...
noexcept
124
noexcept conditionnel (2)
struct bar
{
void operator()(int) noexcept {}
};
struct baz
{
void operator()(int){...
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 fon...
constexpr
127
• const : spécifier des interfaces
- foo(const std::vector<int>&);
• constexpr : spécifier ce qui est utilisab...
constexpr
128
auto sz = 3;
// ERROR: sz's value not known at compilation
constexpr auto sz1 = sz;
// ERROR: sz's value not...
constexpr
129
const auto sz = 3;
// OK: sz's value is known at compilation
constexpr auto sz1 = sz;
// OK: sz's value is k...
constexpr
130
fonctions
constexpr
int foo(int a)
{
return a + 1;
}
constexpr auto x = foo(42);
auto runtime_value = 0u;
st...
constexpr
131
C++11
seulement une expression autorisée
constexpr int fac(int x)
{
return x <= 1
? 1
: x * fac(x-1);
}
cons...
constexpr
132
classes
struct foo
{
int data;
constexpr foo(int d) : data(d) {}
constexpr int operator()() const
{return da...
constexpr
132
classes
struct foo
{
int data;
constexpr foo(int d) : data(d) {}
constexpr int operator()() const
{return da...
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
uns...
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
uns...
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
uns...
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
uns...
constexpr
133
unsigned int f(unsigned int n)
{
return n <= 1
? 1
: n * f(n-1);
}
int main()
{
return f(5);
}
constexpr
uns...
static_assert
134
#include <type_traits>
template <typename T>
constexpr bool
is_power_of_two(T x)
{
static_assert( std::i...
static_assert
134
#include <type_traits>
template <typename T>
constexpr bool
is_power_of_two(T x)
{
static_assert( std::i...
TEMPLATES
Généricité
136
struct foo_vector
{
foo* data;
unsigned int sz;
void push_back(const foo& x)
{
data[sz++] = x;
}
};
une néc...
Généricité
137
struct int_vector
{
int* data;
unsigned int sz;
void push_back(const int& x)
{
data[sz++] = x;
}
};
une néc...
Généricité
138
template <typename T>
struct vector
{
T* data;
unsigned int sz;
void push_back(const T& 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...
Généricité
139
int sum(const std::vector<int>& vec)
{
auto acc = int{};
for (const auto& x : vec)
acc = acc + x;
return ac...
Généricité
140
int sum(const std::vector<int>& vec)
{
auto acc = int{};
for (const auto& x : vec)
acc = acc + x;
return ac...
Généricité
141
template <typename T>
T sum(const std::vector<T>& vec)
{
auto acc = T{};
for (const auto& x : vec)
{
acc = ...
Généricité
141
template <typename T>
T sum(const std::vector<T>& vec)
{
auto acc = T{};
for (const auto& x : vec)
{
acc = ...
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_...
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_...
Structures templates
142
template <typename T>
struct foo
{
T x_;
foo(const T& x) : x_(x) {}
const T& x() const {return x_...
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename ...
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename ...
Fonctions templates
143
struct foo{};
template <typename T, typename U>
void fun0(const T&, const U&);
template <typename ...
Fonctions templates
144
template <typename T>
struct foo
{
T x;
};
template <typename T>
foo<T> mk_foo(const T& x)
{
retur...
Fonctions templates
144
template <typename T>
struct foo
{
T x;
};
template <typename T>
foo<T> mk_foo(const T& x)
{
retur...
Fonctions templates
145
les fonctions membres peuvent être aussi génériques
template <typename T>
struct foo
{
T x_;
foo(c...
Fonctions templates
145
les fonctions membres peuvent être aussi génériques
template <typename T>
struct foo
{
T x_;
foo(c...
Templates :“fabriques”
146
• Une structure template est une “fabrique de type”
‣ template <typename T> struct foo n’est pa...
Accès à un type imbriqué
147
struct bar
{
typedef int value_type;
};
void foo(const bar&)
{
bar::value_type x;
}
dans un c...
Accès à un type imbriqué
147
struct bar
{
typedef int value_type;
};
void foo(const bar&)
{
bar::value_type x;
}
dans un c...
Accès à un type imbriqué
148
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
T::value_t...
Accès à un type imbriqué
148
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
T::value_t...
Accès à un type imbriqué
149
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
typename T...
Accès à un type imbriqué
149
struct bar
{
typedef int value_type;
};
template <typename T>
void foo(const T&)
{
typename T...
150
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
...
150
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
...
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
...
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
...
151
Dependant templates
struct bar
{
template <typename U>
U get() const {}
};
template <typename T>
void foo(const T& b)
...
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 = …;
usin...
alias
153
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, ...
alias
154
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, ...
alias
154
template <typename T, typename U>
struct foo{};
template <typename T>
struct templated_typedef
{
typedef foo<T, ...
alias
155
template <typename T, typename U>
struct foo{};
template <typename T>
using alias_t = foo<T, int>;
int main()
{
...
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
deux types à déduire
template <type...
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
templ...
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type ...
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type ...
Règles de déductions
156
template <typename T>
void f(ParamType param);
f(expression);
type deT
deux types à déduire
type ...
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ére...
Règles de déductions
158
ParamType : pointeur ou référence (1)
template <typename T>
void f(T& param);
int x = 2;
const in...
Règles de déductions
158
ParamType : pointeur ou référence (1)
template <typename T>
void f(T& param);
int x = 2;
const in...
Règles de déductions
159
ParamType : pointeur ou référence (2)
template <typename T>
void f(const T& param);
int x = 2;
co...
Règles de déductions
159
ParamType : pointeur ou référence (2)
template <typename T>
void f(const T& param);
int x = 2;
co...
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...
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...
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...
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x...
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x...
Règles de déductions
161
ParamType : rvalue reference
template <typename T>
void f(T&& param);
int x = 2;
const int cx = x...
162
template <typename T>
void print_type()
{
std::cout << __PRETTY_FUNCTION__;
}
Afficher le type déduit
void print_type()...
163
template <typename T>
void print_type()
{
std::cout << __FUNCSIG__;
}
void _cdecl print_type<struct foo>(void)
(Visual...
164
template <typename T>
struct print_type;
print_type<foo>{};
(tous compilateurs)
Afficher le type déduit
error: implicit...
164
template <typename T>
struct print_type;
print_type<foo>{};
(tous compilateurs)
Afficher le type déduit
ne pas donner d...
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T...
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T...
Spécialisation
165
scénario : un algorithme peut-être optimisé pour un type particulier
struct foo{};
template <typename T...
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
...
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
...
Spécialisation
166
fonctions
struct foo{};
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
template <>
...
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
temp...
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
temp...
Spécialisation
167
fonctions, une petite surprise…
template <typename T>
void algo(const T&)
{
std::cout << "O(n)";
}
temp...
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template ...
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template ...
Spécialisation partielle
168
scénario : un algorithme peut-être optimisé pour un
conteneur générique particulier
template ...
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator(...
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator(...
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator(...
Spécialisation partielle
169
on peut garder des spécialisations totales
template <typename T>
struct algo
{
void operator(...
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> cl...
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> cl...
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> cl...
Template-template arguments
170
template <typename T>
struct vector {};
template <typename T, template <typename DUMMY> cl...
Template-template arguments
171
template <typename T, template <typename> class Container>
struct foo
{
Container<T> cont_...
Template-template arguments
171
template <typename T, template <typename> class Container>
struct foo
{
Container<T> cont_...
Valeurs en paramètres template
172
template <int Value>
struct foo
{
void operator()() const
{
std::cout << Value;
}
};
fo...
Valeurs en paramètres template
173
expressions constantes seulement
template <int Value>
struct foo;
const auto i = 42;
au...
Valeurs en paramètres template
173
expressions constantes seulement
template <int Value>
struct foo;
const auto i = 42;
au...
Valeurs en paramètres template
174
la spécialisation fonctionne aussi
template <int Value>
struct fact
{
static const auto...
Valeurs en paramètres template
174
la spécialisation fonctionne aussi
template <int Value>
struct fact
{
static const auto...
Curiously RecurringTemplate Pattern (CRTP)
175
template <typename T>
struct foo
{};
struct bar
: public foo<bar>
{};
class...
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts......
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts......
Variadic templates
176
template<typename T>
T add(T x)
{
return x;
}
template<typename T, typename... Ts>
T add(T x, Ts......
Variadic templates
177
int add(int arg1)
{
return arg1;
}
int add(int arg1, int arg2)
{
return arg1 + add(arg2);
}
int add...
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
templat...
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
templat...
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
templat...
Variadic templates
178
raisonnement programmation fonctionnelle pure
template<typename T>
T add(T x)
{
return v;
}
templat...
Variadic templates
179
template<typename T>
T add(T v)
{
return v;
}
template<typename T, typename... Args>
T add(T first,...
Variadic templates
180
// Signature of a meta-function that add integers
template <int... Xs>
struct add;
template <int X,...
Variadic templates
181
connaître la taille d’un pack avec sizeof...
template <typename... Ts>
std::size_t foo()
{
return s...
Variadic templates
182
expansion d’un pack (1)
template <typename... Ts>
struct foo{};
template<typename X, typename Y, ty...
Variadic templates
182
expansion d’un pack (1)
template <typename... Ts>
struct foo{};
template<typename X, typename Y, ty...
Variadic templates
183
expansion d’un pack (2)
template<typename... Values>
std::array<int, sizeof...(Values)>
make_array(...
Variadic templates
184
expansion d’un pack : héritage
struct base1
{
void foo(){}
};
struct base2
{
void bar(){}
};
templa...
Variadic templates
185
spécialisation
template <typename... Ts>
struct foo
{};
template <typename... Ts>
struct bar;
templ...
Variadic templates
185
spécialisation
template <typename... Ts>
struct foo
{};
template <typename... Ts>
struct bar;
templ...
Variadic templates
186
template <typename... Ts>
struct tuple {};
template <typename T, typename... Ts>
struct tuple<T, Ts...
Références universelles
187
template <typename T>
void f(T&& param);
• Dénomination de Scott Meyers
• En présence d’une dé...
Références universelles
187
template <typename T>
void f(T&& param);
• Dénomination de Scott Meyers
• En présence d’une dé...
Perfect forwarding
188
le problème : passer des paramètres
de manière transparente à une sous-fonction
template <typename ...
Perfect forwarding
solution : std::forward
template <typename Fun, typename Arg>
void logger(Arg&& x)
{
std::cout << "befo...
Perfect forwarding
190
comment ça fonctionne? (1)
A& & → A&
A& && → A&
A&& & → A&
A&& && → A&&
si invocation f(a)
a de typ...
Perfect forwarding
191
comment ça fonctionne? (2)
template<class T>
T&&
forward(typename remove_reference<T>::type& a)
{
r...
Perfect forwarding
192
void logger(X& && x)
{
std::cout << "beforen";
Fun{}(std::forward<X&>(x));
std::cout << "aftern";
}...
Perfect forwarding
193
sur une rvalue
void logger(X&& && x)
{
std::cout << "beforen";
Fun{}(std::forward<X&&>(x));
std::co...
Perfect forwarding vs move
194
void foo(int&&) {std::cout << "int&&";}
void foo(const int&) {std::cout << "const int&";}
v...
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); /...
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;
}
appe...
198
next/prev
auto vec = std::vector<int>{1,2,3};
auto it = begin(vec);
auto it1 = next(it); // return a copy incremented ...
199
move
déplacer un conteneur
auto vec1 = std::vector<foo>{foo{}, foo{}};
auto vec2 = std::vector<foo>{};
std::cout << ve...
200
all_of, any_of, any_of
auto vec1 = std::vector<bool>{true, true, true};
auto vec2 = std::vector<bool>{true, false, tru...
201
emplace, emplace_back
construction en place grâce au perfect forwarding
struct foo
{
foo(int)
{std::cout << "foo(int)"...
202
shrink_to_fit
deque, string et vector
auto vec1 = std::vector<int>{};
std::cout << vec1.capacity();
vec1.push_back(1);...
203
forward_list
liste simplement chaînée
auto l = std::forward_list<int>{1,2,3};
std::cout << l.size(); // error, no size...
204
array
auto a1 = std::array<int, 3>{};
const auto cit = a1.cbegin();
const auto& x = a1[2]; // use like a C-array
const...
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] =...
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 i...
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)...
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()...
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, ...
209
tuple
permet de retourner plusieurs valeurs
sans avoir à créer un nouveau type (1)
struct foo {};
std::tuple<int, foo>...
210
tuple
permet de retourner plusieurs valeurs
sans avoir à créer un nouveau type (2)
struct foo {};
std::tuple<int, foo>...
211
tuple
concaténer des tuples
auto t0 = std::make_tuple(1, foo{}, 'a');
std::cout << std::tuple_size<decltype(t0)>::valu...
212
unordered_map
table de hachage
auto map = std::unordered_map<int, std::string>{};
map.insert({42, "abc"});
map.emplace...
213
unordered_map
fonctions spécifiques aux tables de hachage
auto map = std::unordered_map<int, std::string>{1'000'000};
p...
214
unordered_map
utiliser un type personnalisé en tant que clé
namespace std
{
template <>
struct hash<foo>
{
std::size_t...
214
unordered_map
utiliser un type personnalisé en tant que clé
namespace std
{
template <>
struct hash<foo>
{
std::size_t...
215
unordered_map
bonus: combiner des valeurs de hachage (1)
/// @brief Combine the hash value of x with seed.
///
/// Tak...
216
unordered_map
bonus: combiner des valeurs de hachage (2)
namespace std
{
template <>
struct hash<foo>
{
std::size_t
op...
217
Gestion de la mémoire
• introduction de unique_ptr
‣ auto_ptr deprecated
‣ utilise les portées pour désallouer
• intro...
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
Prochain SlideShare
Chargement dans…5
×

C++ 11/14

332 vues

Publié le

Un tour d'horizon des nouveautés du C++ 11/14

Publié dans : Logiciels
0 commentaire
0 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Aucun téléchargement
Vues
Nombre de vues
332
Sur SlideShare
0
Issues des intégrations
0
Intégrations
11
Actions
Partages
0
Téléchargements
8
Commentaires
0
J’aime
0
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

C++ 11/14

  1. 1. Alexandre Hamez alexandre.hamez@gmail.com C++ 11/14
  2. 2. PRÉSENTATION GÉNÉRALE
  3. 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. 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. 5. 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 ...
  6. 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
  7. 7. 7 http://en.cppreference.com
  8. 8. C++11/14
  9. 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. 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. 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. 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. 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. 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. 15. Boucles simplifiées 13 const int tab[] = {1,2,3}; for (int x : tab) { std::cout << x << 'n'; } tableaux C
  16. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 50. initializer_list 39 for (auto x : {1,2,3,4}) { std::cout << x << ','; } utilisable dans une boucle simplifiée
  51. 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. 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. 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. 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. 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. 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. 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. 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. 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. 60. User-defined literals 47 struct point { //??? }; // Yaye! const auto p = 3_x + 5_y; comment obtenir cette construction?
  61. 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. 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. 63. Binary literals 50 const auto b = 0b00101010; std::cout << b; // 42 C++14 uniquement
  64. 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. 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. 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. 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. 68. enum class 54 enum e {pink, white, orange, brown}; if (pink < 99.3) { // ... } enum C++03 : conversion implicite dangereuse
  69. 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. 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. 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. 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. 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. 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. 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. 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. 77. nullptr 61 const auto x = f(); if (x == 0) { // ... } plus de clarté const auto x = f(); if (x == nullptr) { // ... } vs
  78. 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. 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. 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. 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. 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. 83. Classes 66 délégation de constructeurs (1) struct foo { const int x_; foo(int x) : x_{x} {} foo() : foo{42} {} };
  84. 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. 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. 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. 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. 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. 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. 90. Classes 70 initialisation directe des attributs struct foo { const int x_ = 33; foo(int x) : x_(x) {} foo() {} };
  91. 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. 92. Classes 71 contrôle de l’héritage avec final struct foo final {}; struct bar : foo {};
  93. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 105. Rvalues references 80 int foo() {return 2;} int main() { foo() = 2; } error: lvalue required as left operand of assignment foo() = 2; ^
  106. 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. 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. 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. 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. 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. 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. 112. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42});
  113. 113. Rvalues references 85 struct foo{int x;}; void bar(foo&& f) { std::cout << f.x << 'n'; } //... bar(foo{42}); foo&& : rvalue reference
  114. 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. 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. 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. 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. 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. 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. 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. 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
  122. 122. Ressource2Ressource1 Move semantics 89 A B
  123. 123. X Ressource1 Move semantics 89 A B
  124. 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. 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. 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. 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. 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. 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. 130. Move semantics 93 struct foo { foo() = default; foo(const foo&) = default; foo(foo&&) = delete; }; int main() { const auto f = foo{}; }
  131. 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. 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. 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. 134. Move semantics 96 struct foo; foo bar() { auto f = foo{}; // later... return std::move(f); } std::move en retour d’une fonction
  135. 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. 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. 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. 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. 139. trailing return type 100 auto foo() -> int { return 42; } std::cout << foo(); type de retour après les paramètres
  140. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 169. noexcept 123 noexcept conditionnel (1) void bar() noexcept { // shall not throw any exception } void foo() noexcept(noexcept(bar())) { bar(); }
  170. 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. 171. noexcept 125 noexcept appliqué aux lambdas const auto lambda = [](int x) noexcept {return x + 40;}; std::cout << lambda(2);
  172. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  187. 187. TEMPLATES
  188. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 218. alias 152 // the old way typedef int my_typedef; // aliases using my_alias = int; using : successeur de typedef
  219. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 271. Curiously RecurringTemplate Pattern (CRTP) 175 template <typename T> struct foo {}; struct bar : public foo<bar> {}; classe héritée générique
  272. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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;
  299. 299. BIBLIOTHÈQUE STANDARD
  300. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

×