lang:cpp:template
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
lang:cpp:template [2020/04/26 23:00] – Conversion de <note> vers <WRAP> root | lang:cpp:template [2025/02/05 10:07] (Version actuelle) – [const Args...] : fix typo root | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
+ | =====Restriction===== | ||
+ | |||
+ | ====Auto déduction==== | ||
+ | |||
+ | Il n'est pas possible de faire de l' | ||
+ | |||
+ | <code cpp> | ||
+ | typename< | ||
+ | R fonction() | ||
+ | { | ||
+ | return 1; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Il faut utiliser '' | ||
+ | |||
+ | <code cpp> | ||
+ | auto fonction() | ||
+ | { | ||
+ | return 1; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ====const Args...==== | ||
+ | |||
+ | Il faut éviter les '' | ||
+ | |||
+ | Sinon, cela impose l' | ||
+ | |||
+ | <code cpp> | ||
+ | template< | ||
+ | void f(const Args&& | ||
+ | |||
+ | f(1.2); | ||
+ | </ | ||
+ | |||
+ | J'ai déjà eu des codes plus complexes où cela posait problème. | ||
+ | |||
=====Héritage===== | =====Héritage===== | ||
====CRTP (Curiously recurring template pattern)==== | ====CRTP (Curiously recurring template pattern)==== | ||
Ligne 254: | Ligne 292: | ||
< | < | ||
+ | |||
+ | =====Divers===== | ||
====Avantages/ | ====Avantages/ | ||
* Avantages | * Avantages | ||
Ligne 266: | Ligne 306: | ||
====Séparer le code source des fonctions et leur définition dans une classe template==== | ====Séparer le code source des fonctions et leur définition dans une classe template==== | ||
+ | |||
+ | * Exemple avec une classe template | ||
+ | |||
C'est possible de ne pas être obligé de rendre '' | C'est possible de ne pas être obligé de rendre '' | ||
Ligne 285: | Ligne 328: | ||
void T< | void T< | ||
+ | // On instancie uniquement T< | ||
template class T< | template class T< | ||
</ | </ | ||
Ligne 294: | Ligne 338: | ||
<file cpp main.cc> | <file cpp main.cc> | ||
#include " | #include " | ||
- | |||
- | extern template class T< | ||
int main() | int main() | ||
{ | { | ||
T< | T< | ||
- | return tint.retval(); | + | return tint.fff(); |
} | } | ||
</ | </ | ||
- | ====Afficher en string le type template==== | + | * Exemple avec une fonction |
- | <code cpp> | + | |
- | typeid(T).name(); | + | |
- | </ | + | |
- | [[https:// | + | < |
- | + | class A { | |
- | [[https:// | + | template< |
- | + | | |
- | [[https:// | + | |
- | + | ||
- | ====Décorateur==== | + | |
- | + | ||
- | [[https:// | + | |
- | + | ||
- | * implicit return type | + | |
- | <code cpp> | + | |
- | #include < | + | |
- | #include < | + | |
- | + | ||
- | struct Action1 { }; | + | |
- | struct Action2 { }; | + | |
- | + | ||
- | class Classe | + | |
- | { | + | |
- | public: | + | |
- | // Default template. | + | |
- | template< | + | |
- | | + | |
- | { | + | |
- | // | + | |
- | } | + | |
}; | }; | ||
+ | </ | ||
- | // Action 1. | + | <file cpp file.cpp> |
- | template<> | + | template< |
- | auto Classe::go< | + | |
- | { | + | |
- | std::cout << " | + | |
- | } | + | |
- | // Action 2. | + | // Instanciation pour U=int |
- | template<> | + | template |
- | auto Classe::go<Action2> | + | |
- | { | + | |
- | std::cout << " | + | |
- | return static_cast< | + | |
- | } | + | |
- | template <class T> | + | // Spécialisation pour U=double |
- | class Decorator | + | template<> |
- | { | + | </ |
- | public: | + | |
- | Decorator(std::unique_ptr<T> t): | + | |
- | | + | * Exemple avec une fonction |
- | auto go(Args ...args) | + | |
- | { | + | |
- | std::cout << " | + | |
- | return | + | |
- | } | + | |
- | private: | + | |
- | std:: | + | |
- | }; | + | |
- | </ | + | |
- | * explicit return type | + | <file cpp file.h> |
- | + | template<typename T> | |
- | <code cpp> | + | class A { |
- | # | + | template< |
- | #include < | + | |
- | + | ||
- | struct Action1 { using Type = void; }; | + | |
- | struct Action2 { using Type = char; }; | + | |
- | + | ||
- | class Classe | + | |
- | { | + | |
- | public: | + | |
- | // Default template. | + | |
- | template< | + | |
- | | + | |
- | { | + | |
- | // | + | |
- | } | + | |
}; | }; | ||
- | |||
- | // Action 1. | ||
- | template<> | ||
- | Action1:: | ||
- | { | ||
- | std::cout << " | ||
- | } | ||
- | |||
- | // Action 2. | ||
- | template<> | ||
- | Action2:: | ||
- | { | ||
- | std::cout << " | ||
- | return i; | ||
- | } | ||
- | |||
- | template <class T> | ||
- | class Decorator | ||
- | { | ||
- | public: | ||
- | Decorator(std:: | ||
- | |||
- | template< | ||
- | auto go(Args ...args) | ||
- | { | ||
- | std::cout << " | ||
- | return classe-> | ||
- | } | ||
- | private: | ||
- | std:: | ||
- | }; | ||
- | </ | ||
- | |||
- | * main.cc | ||
- | |||
- | <code cpp> | ||
- | int main() | ||
- | { | ||
- | Decorator< | ||
- | c.go< | ||
- | c.go< | ||
- | } | ||
- | </ | ||
- | |||
- | ====metaprogrammation vs constexpr==== | ||
- | ===Exemple simple=== | ||
- | <code cpp> | ||
- | #include < | ||
- | |||
- | template < | ||
- | constexpr T square(T x) { | ||
- | return x*x; | ||
- | } | ||
- | |||
- | int main() { | ||
- | printf(" | ||
- | // 11.560000 9 | ||
- | } | ||
- | </ | ||
- | |||
- | ===Fibonacci=== | ||
- | |||
- | * Template | ||
- | |||
- | <file cpp fibonacci.cc> | ||
- | template <long N> struct fibonacci | ||
- | { | ||
- | static const long value = fibonacci< | ||
- | }; | ||
- | |||
- | template <> struct fibonacci< | ||
- | { | ||
- | static const long value = 1; | ||
- | }; | ||
- | |||
- | template <> struct fibonacci< | ||
- | { | ||
- | static const long value = 1; | ||
- | }; | ||
- | |||
- | int main() | ||
- | { | ||
- | long i = fibonacci< | ||
- | return 0; | ||
- | } | ||
</ | </ | ||
- | gcc et clang génère 190392490709135 avec succès. | + | <file cpp file.cpp> |
+ | template< | ||
- | * constexpr | + | template void A<int>::f(short u); |
- | + | ||
- | <file cpp fibonacci2.cc> | + | |
- | constexpr long fib(long n) | + | |
- | { | + | |
- | if (n <= 2) { | + | |
- | return 1; | + | |
- | } | + | |
- | return fib(n - 1) + fib(n - 2); | + | |
- | } | + | |
- | + | ||
- | int main() | + | |
- | { | + | |
- | constexpr long i = fib(70); | + | |
- | return 0; | + | |
- | } | + | |
</ | </ | ||
- | gcc arrive à calculer jusqu'à la valeur 35 et clang jusqu' | + | * Messages d'erreur |
- | <WRAP center round important 60%> | + | '' |
- | Le code est beaucoup moins optimisé dans cette version avec constexpr. Il aurait fallu d'abord remplir un tableau de 70 valeurs (ce que fait le compilateur dans la première version en calculant les '' | + | |
- | </ | + | |
- | ===Nombres premiers=== | + | '' |
- | * Template | + | '' |
- | [[https:// | + | Il ne faut pas utiliser une classe spécialisée avant qu' |
- | [[https:// | + | < |
+ | template | ||
+ | class A {}; | ||
- | <file cpp prime.cc> | + | // Doit être défini après la spécialisation. |
- | #include < | + | A< |
- | + | ||
- | template <int N> | + | |
- | struct Sqrt { | + | |
- | template <int lo, int hi> | + | |
- | struct Helper { | + | |
- | static const int mid = (lo + hi + 1) / 2; | + | |
- | static const int value = std:: | + | |
- | }; | + | |
- | template | + | |
- | struct Helper <n, n> { | + | |
- | static const int value = n; | + | |
- | }; | + | |
- | static const int value = Helper <0, N>:: | + | |
- | }; | + | |
- | + | ||
- | template <long x, long max_odd> struct is_prime_to_max_odd { | + | |
- | static bool const value = x % max_odd != 0 && | + | |
- | is_prime_to_max_odd< | + | |
- | }; | + | |
- | + | ||
- | template <long x> struct is_prime_to_max_odd< | + | |
- | + | ||
- | template <long x> struct max_prime_compare { | + | |
- | static long const tmp = Sqrt< | + | |
- | }; | + | |
- | + | ||
- | template <long x, bool disable> struct check_odd { | + | |
- | static bool const value = is_prime_to_max_odd< | + | |
- | }; | + | |
- | + | ||
- | template <long x> struct check_odd <x, true> { | + | |
- | static bool const value = false; | + | |
- | }; | + | |
- | + | ||
- | template <long x> struct is_prime { | + | |
- | static bool const value = check_odd< | + | |
- | }; | + | |
- | + | ||
- | template <> struct is_prime <1> : std:: | + | |
- | template <> struct is_prime <2> : std:: | + | |
- | + | ||
- | int main() { | + | |
- | bool b49991 = is_prime< | + | |
- | bool b49992 = is_prime< | + | |
- | bool b49993 = is_prime< | + | |
- | return 0; | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | gcc et clang arrive à calculer à la compilation. | + | |
- | + | ||
- | ====Appeler la méthode généralisée depuis la méthode spécialisée==== | + | |
- | C'est impossible. Il faut que la méthode de base appelle une méthode spécifique. | + | |
+ | template <> | ||
+ | class A< | ||
+ | </ | ||
+ | ====Afficher en string le type template==== | ||
<code cpp> | <code cpp> | ||
- | template< | + | typeid(T).name(); |
- | void baseF(T t) { ... } | + | </ |
- | template< | + | [[https:// |
- | void F(T t) { baseF< | + | |
- | template<> | + | [[https:// |
- | void F< | + | |
- | </code> | + | |
- | [[https:// | + | [[https:// |
====class ou typename==== | ====class ou typename==== | ||
Ligne 730: | Ligne 563: | ||
AA2< | AA2< | ||
} | } | ||
+ | </ | ||
+ | |||
+ | ====Sérialisation==== | ||
+ | |||
+ | Compter le nombre de champ d'une classe. | ||
+ | |||
+ | <code cpp> | ||
+ | #include < | ||
+ | |||
+ | struct UniversalType { | ||
+ | template < | ||
+ | operator T(); // no definition required | ||
+ | }; | ||
+ | |||
+ | template < | ||
+ | consteval auto MemberCounter(auto... c0) { | ||
+ | if constexpr (requires { T{{A0{}}..., | ||
+ | return MemberCounter< | ||
+ | else if constexpr ( | ||
+ | requires { | ||
+ | T{{A0{}}..., | ||
+ | } || | ||
+ | requires { | ||
+ | T{{A0{}}..., | ||
+ | }) | ||
+ | return MemberCounter< | ||
+ | return sizeof...(A0) + sizeof...(c0); | ||
+ | } | ||
+ | |||
+ | int main() { | ||
+ | using TestType = struct { | ||
+ | int x[3]; | ||
+ | float y; | ||
+ | char z; | ||
+ | }; | ||
+ | auto [a, b, c] = TestType{}; | ||
+ | std::cout << MemberCounter< | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ====Erreurs==== | ||
+ | |||
+ | * Il manque un mot clé '' | ||
+ | |||
+ | Il faut parfois rajouter le mot clé '' | ||
+ | |||
+ | <code cpp> | ||
+ | error: ' | ||
+ | return T::template f< | ||
+ | | ||
+ | </ | ||
+ | |||
+ | <code cpp> | ||
+ | return T::template f< | ||
+ | </ | ||
+ | |||
+ | * Il manque un mot clé '' | ||
+ | |||
+ | <code cpp> | ||
+ | error: expected ';' | ||
+ | retval-> | ||
+ | ^ | ||
+ | ; | ||
+ | </ | ||
+ | |||
+ | ou encore | ||
+ | |||
+ | <code cpp> | ||
+ | error: expression contains unexpanded parameter pack ' | ||
+ | retval-> | ||
+ | ^ ~ | ||
+ | </ | ||
+ | |||
+ | ou encore | ||
+ | |||
+ | <code cpp> | ||
+ | error: expected primary-expression before ' | ||
+ | return this-> | ||
+ | ^ | ||
+ | </ | ||
+ | |||
+ | Solution: | ||
+ | |||
+ | <code cpp> | ||
+ | retval-> | ||
+ | </ | ||
+ | |||
+ | ===Mapping d'un type vers un autre via une map=== | ||
+ | |||
+ | https:// | ||
+ | |||
+ | < | ||
+ | using my_map = type_map< | ||
+ | pair< | ||
+ | pair< | ||
+ | pair< | ||
+ | >; | ||
+ | |||
+ | static_assert(std:: | ||
+ | static_assert(std:: | ||
+ | static_assert(std:: | ||
+ | </ | ||
+ | |||
+ | <code cpp> | ||
+ | template < | ||
+ | struct type_tag | ||
+ | { | ||
+ | using type = T; | ||
+ | }; | ||
+ | |||
+ | template < | ||
+ | struct pair | ||
+ | { | ||
+ | using first_type = K; | ||
+ | using second_type = V; | ||
+ | }; | ||
+ | |||
+ | template < | ||
+ | struct element | ||
+ | { | ||
+ | static auto value(type_tag< | ||
+ | -> type_tag< | ||
+ | }; | ||
+ | |||
+ | template < | ||
+ | struct type_map : element< | ||
+ | { | ||
+ | using element< | ||
+ | |||
+ | template < | ||
+ | using find = typename decltype(type_map:: | ||
+ | }; | ||
</ | </ |
lang/cpp/template.1587934809.txt.gz · Dernière modification : 2020/04/26 23:00 de root