Outils pour utilisateurs

Outils du site


lang:cpp:templatespecialisation

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
lang:cpp:templatespecialisation [2025/11/14 11:33] – [Il faut commencer par spécialiser le premier template] : précision : surcharge rootlang:cpp:templatespecialisation [2025/11/14 12:02] (Version actuelle) – Réécriture complète root
Ligne 1: Ligne 1:
-====Spécialisation partielle====+=====Spécialisation complète=====
  
-===Il faut commencer par spécialiser le premier template===+====Appeler la méthode généralisée depuis la méthode spécialisée====
  
-  * Classe template+C'est impossible. La solution est que la méthode de base s'appelle autrement.
  
 <code cpp> <code cpp>
 template<typename T> template<typename T>
-class A +void baseF(T t) ... }
-{ +
-    template<typename U> +
-    class B +
-    { +
-    }; +
-};+
  
-// OK 
-template<> 
-template<typename U> 
-class A<int>::B 
-{ 
-    int b; 
-}; 
- 
-// KO 
 template<typename T> template<typename T>
-template<> +void F(T t) { baseF<T>(t); }
-class A<T>::B<int> +
-+
-    int b; +
-};+
  
 +template<>
 +void F<int>(int t) { baseF<int>(t); }
 </code> </code>
  
-  * Fonction template+[[https://stackoverflow.com/questions/6674795/how-to-call-generic-template-function-in-a-specialization-version|How to call generic template function in a specialization version]] {{ :lang:cpp:template:c_-_how_to_call_generic_template_function_in_a_specialization_version_-_stack_overflow_2020-02-06_23_35_03_.html |Archive du 13/07/2011 le 06/02/2020}}
  
-Il n'est pas possible de faire de la spécialisation partielle de template comme pour les classes.+====Empêcher l'utilisation du template non spécialisé====
  
-Mais il est possible d'activer certaines spécialisations de template en fonction du type.+''static_assert(false)'' ne peut être utilisé directement car il est systématiquement évalué par le compilateur. Il faut ajouter un niveau d'indirection.
  
-''std::enable_if'' permet d'activer sous condition une fonction templateLe premier argument est la condition, le deuxième argument est le type de retour de la fonctionMais c'est de la surchargepas de la spécialisation.+<code cpp> 
 +#include <type_traits> 
 + 
 +template <typename T> 
 +struct foobar : std::false_type {}; 
 + 
 +// Template général. 
 +template <class T> 
 +T fun(T a) { 
 +  // La variable value n'est évaluée que si la méthode est utilisée. 
 +  static_assert(foobar<T>::value, 
 +                "this function has to be implemented for desired type"); 
 +
 + 
 +template <> 
 +int fun(int a) { 
 +  return a; 
 +
 + 
 +int main() { 
 +  // fun<char>('a'); // Echec 
 +  fun<int>(10); 
 +  // fun<float>(10.14); // Echec 
 +
 +</code> 
 + 
 +Autre exemple avec ''std::conditional'':
  
 <code cpp> <code cpp>
 #include <type_traits> #include <type_traits>
  
-struct +struct 
-  using = int;+
 +  using Ty = int;
 }; };
  
-struct { +struct {};
-  using R = float; +
-};+
  
-class A { +// KO, should be OK. 
- public: +// using Ttrue = std::conditional_t<true, A::Ty, B::Ty>
-  template <typename T+// KO 
-  static typename std::enable_if_t<std::is_same_v<TI>, I::Rf() { +// using Tfalse = std::conditional_t<false, A::TyB::Ty>;
-    return 1; +
-  }+
  
-  template <typename T> +template <typename T> 
-  static typename std::enable_if_t<std::is_same_v<T, F>, F::R> f() { +struct LazyLoadIdentity 
-    return 27; +{ 
-  }+  using type = T;
 }; };
  
-int main() return A::f<I>() + A::f<F>()}+template <typename T> 
 +struct LazyLoadTy : LazyLoadIdentity<typename T::Ty> {}; 
 + 
 +// OK 
 +using Ttrue = std::conditional_t<true, LazyLoadTy<A>, LazyLoadTy<B>>::type; 
 +// KO 
 +//using Tfalse = std::conditional_t<false, LazyLoadTy<A>, LazyLoadTy<B>>::type;
 </code> </code>
-====Décorateur====+ 
 +[[https://stackoverflow.com/questions/34281017/is-it-possible-to-build-a-lazy-conditional-metafunction|Is it possible to build a lazy conditional metafunction]] {{ :lang:cpp:template:c_-_is_it_possible_to_build_a_lazy_conditional_metafunction_-_stack_overflow_2021-05-17_22_08_45_.html |Archive du 15/12/2015 le 17/05/2021}} 
 + 
 +====Exemples==== 
 + 
 +===Décorateur (spécialisation sur type)===
  
 [[https://cppcodetips.wordpress.com/2016/10/31/decorator-pattern-explained-with-c-sample/|Decorator Pattern Explained with C++ sample]] {{ :lang:cpp:template:decorator_pattern_explained_with_c_sample_cpp_code_tips_2020-02-05_21_09_42_.html |Archive du 31/10/2016 le 05/02/2020}} [[https://cppcodetips.wordpress.com/2016/10/31/decorator-pattern-explained-with-c-sample/|Decorator Pattern Explained with C++ sample]] {{ :lang:cpp:template:decorator_pattern_explained_with_c_sample_cpp_code_tips_2020-02-05_21_09_42_.html |Archive du 31/10/2016 le 05/02/2020}}
  
-  * implicit return type 
 <code cpp> <code cpp>
 #include <iostream> #include <iostream>
Ligne 122: Ligne 138:
 </code> </code>
  
-  * explicit return type +<file cpp main.cc>
- +
-<code cpp+
-#include <iostream> +
-#include <memory> +
- +
-struct Action1 { using Type = void; }; +
-struct Action2 { using Type = char; }; +
- +
-class Classe +
-+
-public: +
-    // Default template. +
-    template<class U, class T, class ...Args> +
-    T go(Args ...args) +
-    { +
-        //static_assert(false); +
-    } +
-}; +
- +
-// Action 1. +
-template<> +
-Action1::Type Classe::go<Action1>() +
-+
-    std::cout << "coucouGo1" << std::endl; +
-+
- +
-// Action 2. +
-template<> +
-Action2::Type Classe::go<Action2>(int i) +
-+
-    std::cout << "coucouGo2 : " << i << std::endl; +
-    return i; +
-+
- +
-template <class T> +
-class Decorator +
-+
-public: +
-    Decorator(std::unique_ptr<T> t):classe(std::move(t)) {} +
- +
-    template<class U, class... Args> +
-    auto go(Args ...args) +
-    { +
-        std::cout << "coucouDecorator" << std::endl; +
-        return classe->template go<U, typename U::Type>(args...); +
-    } +
-    private: +
-        std::unique_ptr<T> classe; +
-}; +
-</code> +
- +
-  * main.cc +
- +
-<code cpp>+
 int main() int main()
 { {
Ligne 183: Ligne 145:
     c.go<Action2>(2);     c.go<Action2>(2);
 } }
-</code> +</file>
- +
-====metaprogrammation vs constexpr==== +
-===Exemple simple=== +
-<code cpp> +
-#include <cstdio> +
- +
-template <typename T> +
-constexpr T square(T x) { +
-  return x*x; +
-+
- +
-int main() { +
-  printf("%lf %d\n", square(3.4), square<int>(3.4)); +
-  // 11.560000 9 +
-+
-</code>+
  
-===Fibonacci===+===Fibonacci (spécialisation sur valeur)===
  
   * Template   * Template
Ligne 251: Ligne 197:
  
 <WRAP center round important 60%> <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 ''static value'') ce qui aurait permis d'éviter d'avoir une récursion très longue de 70 étapes.+Le code est beaucoup moins optimisé 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 ''static value'') ce qui aurait permis d'éviter d'avoir une récursion très longue de 70 étapes.
 </WRAP> </WRAP>
  
-===Nombres premiers===+===Nombres premiers (spécialisation par valeur)===
  
   * Template   * Template
Ligne 315: Ligne 261:
 gcc et clang arrive à calculer à la compilation. gcc et clang arrive à calculer à la compilation.
  
-====Appeler la méthode généralisée depuis la méthode spécialisée==== +=====Spécialisation partielle===== 
-C'est impossible. Il faut que la méthode de base appelle une méthode spécifique.+ 
 +====Template imbriqué==== 
 + 
 +Il faut spécialiser le template parent avant de pouvoir spécialiser le template enfant. 
 + 
 +  * Classe template
  
 <code cpp> <code cpp>
 template<typename T> template<typename T>
-void baseF(T t) ... }+class A 
 +{ 
 +    template<typename U> 
 +    class B 
 +    { 
 +    }; 
 +};
  
-template<typename T+// OK 
-void F(T t) { baseF<T>(t); }+template<> 
 +template<typename U
 +class A<int>::B 
 +
 +    int b; 
 +};
  
 +// KO
 +template<typename T>
 template<> template<>
-void F<int>(int t) { baseF<int>(t); }+class A<T>::B<int> 
 +
 +    int b; 
 +}
 </code> </code>
  
-[[https://stackoverflow.com/questions/6674795/how-to-call-generic-template-function-in-a-specialization-version|How to call generic template function in a specialization version]] {{ :lang:cpp:template:c_-_how_to_call_generic_template_function_in_a_specialization_version_-_stack_overflow_2020-02-06_23_35_03_.html |Archive du 13/07/2011 le 06/02/2020}}+====Fonction template====
  
-====Divers====+Il n'est pas possible de faire de la spécialisation partielle de template comme pour les classes.
  
-===Empêcher l'utilisation du template non spécialisé===+  * ''enable_if''
  
-''static_assert(false)'' ne peut être utilisé directement car il est systématiquement évalué par le compilateurIl faut ajouter un niveau d'indirection.+Il est possible d'activer certaines spécialisations de template en fonction du type. Mais c'est de la surcharge, pas de la spécialisation. Il faut bien vérifier que les ''enable_if'' soit bien mutuellement exclusifs donc il ne doit pas y avoir le fonction générique mais uniquement des fonctions spécialisées. 
 + 
 +''std::enable_if'' permet d'activer sous condition une fonction template. Le premier argument est la condition, le deuxième argument est le type de retour de la fonction.
  
 <code cpp> <code cpp>
 #include <type_traits> #include <type_traits>
  
-template <typename T> +struct { 
-struct foobar : std::false_type {};+  using R = int; 
 +};
  
-// Template général. +struct F 
-template <class T> +  using R = float
-T fun(T a) +};
-  // La variable value n'est évaluée que si la méthode est utilisée. +
-  static_assert(foobar<T>::value, +
-                "this function has to be implemented for desired type")+
-}+
  
-template <> +class A { 
-int fun(int a) { + public: 
-  return a+  template <typename T
-}+  static typename std::enable_if_t<std::is_same_v<T, I>, I::R> f() { 
 +    return 1
 +  }
  
-int main() { +  template <typename T> 
-  // fun<char>('a'); // Echec +  static typename std::enable_if_t<std::is_same_v<T, F>, F::Rf() 
-  fun<int>(10)+    return 27
-  // fun<float>(10.14); // Echec +  
-}+}; 
 + 
 +int main() { return A::f<I>() + A::f<F>(); }
 </code> </code>
  
-Autre exemple avec ''std::conditional'':+  * Utilisation d'une classe 
 + 
 +Si la méthode est static, le plus simple est de passer par des classes qui ne contionnent qu'une seule méthode, celle à spécialiser partiellement.
  
 <code cpp> <code cpp>
-#include <type_traits> +template <typename T, typename U
- +struct A { 
-struct A +    static int foo(U) { return 1}
-+
-  using Ty = int;+
 }; };
- 
-struct B {}; 
- 
-// KO, should be OK. 
-// using Ttrue = std::conditional_t<true, A::Ty, B::Ty>; 
-// KO 
-// using Tfalse = std::conditional_t<false, A::Ty, B::Ty>; 
  
 template <typename T> template <typename T>
-struct LazyLoadIdentity +struct A<T, int> 
-+    static int foo(int) { return 2}
-  using type = T;+
 }; };
- 
-template <typename T> 
-struct LazyLoadTy : LazyLoadIdentity<typename T::Ty> {}; 
- 
-// OK 
-using Ttrue = std::conditional_t<true, LazyLoadTy<A>, LazyLoadTy<B>>::type; 
-// KO 
-//using Tfalse = std::conditional_t<false, LazyLoadTy<A>, LazyLoadTy<B>>::type; 
 </code> </code>
- 
-[[https://stackoverflow.com/questions/34281017/is-it-possible-to-build-a-lazy-conditional-metafunction|Is it possible to build a lazy conditional metafunction]] {{ :lang:cpp:template:c_-_is_it_possible_to_build_a_lazy_conditional_metafunction_-_stack_overflow_2021-05-17_22_08_45_.html |Archive du 15/12/2015 le 17/05/2021}} 
- 
lang/cpp/templatespecialisation.1763116438.txt.gz · Dernière modification : de root