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/03/12 23:06] – [Mixin classes (similaire à CRTP mais sans inversion de l'héritage)] : précision sur le dilemne Mixin 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 108: | Ligne 146: | ||
===Benchmark=== | ===Benchmark=== | ||
- | ^ Performance | + | ^ Performance |
- | | Virtuelle | + | | Virtuelle |
- | | CRTP | 3, | + | | CRTP | 3, |
===Héritage multiple=== | ===Héritage multiple=== | ||
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< | ||
</ | </ | ||
- | <note important> | + | <WRAP center round important |
+ | Si on décide de mettre le '' | ||
+ | </WRAP> | ||
<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 |
- | <note important> | + | '' |
- | </ | + | |
- | ===Nombres premiers=== | + | |
- | * Template | + | '' |
- | [[https:// | + | '' |
- | [[https:// | + | Il ne faut pas utiliser une classe spécialisée avant qu' |
- | <file cpp prime.cc> | + | <code cpp> |
- | # | + | template |
+ | class A {}; | ||
- | template <int N> | + | // Doit être défini après la spécialisation. |
- | struct Sqrt { | + | A< |
- | 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 726: | 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.1584050818.txt.gz · Dernière modification : 2020/03/12 23:06 de root