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 : de root
