Outils pour utilisateurs

Outils du site


lang:cpp:templatespecialisation

Ceci est une ancienne révision du document !


Divers

Empêcher l'utilisation du template non spécialisé

static_assert(false) ne peut être utilisé directement car il est systématiquement évalué par le compilateur. Il faut feinter…

#include <type_traits>
 
template <typename T>
struct foobar : std::false_type {};
 
// Template général.
template <class T>
T fun(T a) {
  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
}

Décorateur

Decorator Pattern Explained with C++ sample Archive du 31/10/2016 le 05/02/2020

  • implicit return type
#include <iostream>
#include <memory>
 
struct Action1 { };
struct Action2 { };
 
class Classe
{
public:
    // Default template.
    template<class U, class ...Args>
    auto go(Args ...args)
    {
        //static_assert(false);
    }
};
 
// Action 1.
template<>
auto Classe::go<Action1>()
{
    std::cout << "coucouGo1" << std::endl;
}
 
// Action 2.
template<>
auto Classe::go<Action2>(int i)
{
    std::cout << "coucouGo2 : " << static_cast<unsigned char>(i) << std::endl;
    return static_cast<unsigned char>(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>(args...);
    }
    private:
        std::unique_ptr<T> classe;
};
  • explicit return type
#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;
};
  • main.cc
int main()
{
    Decorator<Classe> c(std::make_unique<Classe>());
    c.go<Action1>();
    c.go<Action2>(2);
}

metaprogrammation vs constexpr

Exemple simple

#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
}

Fibonacci

  • Template
fibonacci.cc
template <long N> struct fibonacci
{
  static const long value = fibonacci<N - 1>::value + fibonacci<N - 2>::value;
};
 
template <> struct fibonacci<1>
{
  static const long value = 1;
};
 
template <> struct fibonacci<2>
{
  static const long value = 1;
};
 
int main()
{
  long i = fibonacci<70>::value;
  return 0;
}

gcc et clang génère 190392490709135 avec succès.

  • constexpr
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'à 26. Au delà, il faut utiliser -fconstexpr-ops-limit= (2^25 par défaut) pour gcc et -fconstexpr-backtrace-limit=80 -fconstexpr-steps=2147483647 pour clang.

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.

Nombres premiers

  • Template

CppCon 2016: Peter Gottschling “How bad is Meta-Programming still today?"

C++11 Template Metaprogramming — Compile Time Computations Archive du 21/12/2014 le 17/01/2020

prime.cc
#include <type_traits>
 
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::conditional < (N / mid < mid), Helper < lo, mid - 1 >, Helper <mid, hi> >::type::value;
    };
    template <int n>
    struct Helper <n, n> {
        static const int value = n;
    };
    static const int value = Helper <0, N>::value;
};
 
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<x, max_odd-2>::value;
};
 
template <long x> struct is_prime_to_max_odd<x, 1> : std::true_type {};
 
template <long x> struct max_prime_compare {
  static long const tmp = Sqrt<x>::value, value = tmp % 2 == 0 ? tmp + 1 : tmp + 2;
};
 
template <long x, bool disable> struct check_odd {
  static bool const value = is_prime_to_max_odd<x, max_prime_compare<x>::value>::value;
};
 
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<x, x%2==0>::value;
};
 
template <> struct is_prime <1> : std::false_type {};
template <> struct is_prime <2> : std::true_type {};
 
int main() {
  bool b49991 = is_prime<49991>::value;
  bool b49992 = is_prime<49992>::value;
  bool b49993 = is_prime<49993>::value;
  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<typename T>
void baseF(T t) { ... }
 
template<typename T>
void F(T t) { baseF<T>(t); }
 
template<>
void F<int>(int t) { baseF<int>(t); }

How to call generic template function in a specialization version Archive du 13/07/2011 le 06/02/2020

lang/cpp/templatespecialisation.1619003975.txt.gz · Dernière modification : 2021/04/21 13:19 de root