template specialization etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
template specialization etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

20 Kasım 2020 Cuma

Template Specialization - Class Tanımlama

Giriş
Generic bir sınıfın hangi tipler için yaratılabileceğini belirtiriz
Örnek
Açıklaaması şöyle
I have a class A with template argument T, which is limited to two types: T1 and T2. Because of this, I explicitly instantiated class A for types T1 and T2 such that A's functionality can be defined in a source file and doesn't need to be recompiled every time A.hpp is included.
A.hpp dosyasında şöyle yaparız
template<typename T>
class A {
public:
    void basicMethod();
};

template class A<T1>;
template class A<T2>;
A.cpp dosyasında şöyle yaparız
template<typename T>
void A<T>::basicMethod() {
    // ...
}

Template Specialization - Global Metod

Giriş
Bu yazıda iki tane amaç var
1. Template metodu bir parametre tipi için template kullanmadan overload etmek
2. Parametre tipine göre doğru template metodu seçmek

1. Template metodu bir parametre tipi için overload etmek
Örnek - Template Olmayan Overload
Açıklaması şöyle
Non template functions are (let me say) preferred over function templates, thus you can easily got what you pay for in your code with an old plain function.
Şöyle yaparız
template <class T>
int HelloFunction(const T &a) {
  std::cout << "Hello: " << a << std::endl;
  return 0;
}

int HelloFunction(const char *a) {
  std::cout << "Hello: " << a << std::endl;
  return 0;
}

int main() {
  HelloFunction(1);
  HelloFunction("char");
  return 0;
}
Template olan overload derlenmez! Elimizde şöyle bir kod olsun
template <class T>
int HelloFunction(const T& a)
{
  std::cout << "Hello: " << a << std::endl;
  return 0;
}

template <>
int HelloFunction(const char* & a)
{
  std::cout << "Hello: " << a << std::endl;
  return 0;
}

int main()
{
  HelloFunction(1);
  HelloFunction("char");

  return 0;
}
Bu kod derlenmez. İkinci HelloFunction için hata olarak şunu alırız . Burada problem metod parametresinin generic tip olmaması.
error: template-id 'HelloFunction<>' for 'int HelloFunction(const char*&)' does not match
any template declaration
Eğer metod parametresi de generic tip olsaydı derlenirdi. Şu kod derlenir
template<typename T>
struct ABC {
  T type;
  ABC(T inType) : type(inType) {}
};

template <class T>
int HelloFunction(ABC<T>& a)
{
  std::cout << "Hello: " << a.type << std::endl;
  return 0;
}

template <>
int HelloFunction(ABC<const char*> & a)
{
  std::cout << "Hello: " << a.type << std::endl;
  return 0;
}

int main()
{
  HelloFunction(ABC<int>(1));
  HelloFunction(ABC<const char*>("char"));

  return 0;
}
Örnek
Şöyle yaparız. Bu kodda T tipi parametre olarak kullanılıyor
template <class T> 
T foo<T>(T val) { return someFunc(val); }

template <>
bool foo<bool>(bool val) { return otherFunc(val); };
Eğer foo metodunun Bar için derlenmemesini istersek şöyle yaparız.
template <>
Bar foo<Bar>(Bar val) = delete;
Parametre tipine göre doğru template metodu seçmek

Bu yöntemte std::enable_if kullanılır



Template Specialization - Generic Olmayan Sınıf

Giriş
Sınıfımız generic değildir ancak içindeki bir metod generic yani template kullanıyordur. Burada amaç onlarca farklı parametre tipi için tek bir metod yazmak.

Not : Bu yazının ismi Template Specialization ancak amaç aslında belli bir parametre tipine göre farklı bir metodu çağırmak değil. Amaç aynı işi yapan onlarca farklı parametre tipi için ortam metod yazmak

Örnek
Bu yöntemi çok fazla mesajın dispatch edildiği bir template sınıfında kullandım. .h dosyasında şöyle yaparız. Burada sadece metod generic
template <class T>
void doSomething(const T& * msg);
Daha sonra .cpp dosyasında ortak metodu yazarız. Ortak metod gelen mesajı bir kuyruğa yazıyordu. Gerçi kuyrukta her mesaj tipi için farklı bir metod yine yazılmıştı ama olsun :)
template <class T>
void TClass::doSomething(const T& v) {
  ...
}
Her tip için farklı bir specialization metodunu ortak metodun üstüne tanımlarız. int için şöyle yaparız.
template void TClass::doSomething<int>(const int& v);
long için şöyle yaparız.
template void TClass::doSomething<long>(const long& v);
Örnek
Boost Serialization için A.h dosyasında şöyle yaparız. Burada da A sınıfı generic değil
class A {
public:
  ...
private:
  friend class boost::serialization::access;
  template <class Archive> void serialize(Archive&, unsigned);
};
A.cpp dosyasında şöyle yaparız. Böylece aynı serialize() metodu text_iarchive ve text_oarchive için kullanılabilir.
// A.cpp
#include "A.h"

template <class Archive>
void A::serialize(Archive &ar, unsigned) 
{
    ar & bpt; 
}

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "B.h" // required at point of instatiation
template void A::serialize(boost::archive::text_iarchive&, unsigned);
template void A::serialize(boost::archive::text_oarchive&, unsigned);
Örnek
Konunun biraz dışında ama not almak istedim. Eğer sınıfımız generic olsaydı ve sadece T1,T2 tipileri için yaratılsaydı cpp dosyasında şöyle yaparız
template void A<T1>::advancedMethod(S1);
template void A<T1>::advancedMethod(S2);
template void A<T2>::advancedMethod(S1);
template void A<T2>::advancedMethod(S2);