31 Aralık 2019 Salı

SFINAE - T Parametre Tipine Göre

Giriş
std::enable_if <...>+ std::is_same<..> kullanılır.

Yöntemler
Bu ikiliyi kullanmak için iki tane yol var. Bunlar şöyle. İkinci yöntemi terchi etmek gerekir deniliyor.

- Birinci yöntemde std::enable_if<> tek parametre ile kullanılıyor.
- İkinci yöntemde std::is_same_v<...>'in sonucu std::enable_if <..> = X şeklinde kontrol ediliyor.
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
  std::cout << "method 1" << std::endl;
}

template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
  std::cout << "method 2" << std::endl;
}
Örnek
Birinci yöntemde şöyle yaparız. std::enable_if tek parametre ile kullanılıyor.
template <typename T, typename = std::enable_if_t<true == bar<T>()>>
void foo () // version 1
 { }

template <typename T, typename = std::enable_if_t<false == bar<T>()>>
void foo () // version 2
 { }
İkinci yöntemde şöyle yaparız. std::enable_if iki parametre ile kullanılıyor.
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true>
void foo () // version 1
 { }

template <typename T, std::enable_if_t<false == bar<T>(), bool> = true>
void foo () // version 2
 { }
İkinci Yöntemi Tercih Etmek İçin Gerekçe 1
Açıklaması şöyle. Yani derleyici fazladan parametreyi kabul ediyor.
you can (accidentally) pass an explicit type parameter as the second template argument and defeat the SFINAE mechanism completely. This could happen as a typo, copy/paste error, or as an oversight in a larger template mechanism.
Şöyle yaparız.
#include <cstdlib>
#include <type_traits>
#include <iostream>

// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
    std::cout << "method 1" << std::endl;
}

int main(){

    // works fine
    foo<int>();

    // ERROR: subsitution failure, as expected
    // foo<double>();

    // Oops! also works, even though T != int :(
    foo<double, double>();

    return 0;
}
Kullanım Örnekleri
Örnek
Şöyle yaparız.
template<typename T>
class smartPointer
{
private:
  T *mPtr;

  del_member(std::true_type) { delete[] mPtr; }
  del_member(std::false_type) { delete mPtr; }

public:
  // Removed you code for brevity.

  ~smartPointer()
  {   
    del_member(std::is_array<T>{});
  }
};
Örnek
Şöyle yaparız.
template<typename T>
typename std::enable_if<std::is_same<T, INT8>::value 
            || std::is_same<T, UINT8>::value 
            || std::is_same<T, INT16>::value 
            || std::is_same<T, UINT16>::value>::type Function(const T*in, T*out)
{
  Func1(in, out);
}

template<typename T>
typename std::enable_if<std::is_same<T, INT32>::value 
            || std::is_same<T, UINT32>::value >::type Function(const T*in, T*out)
{
  Func2(in, out);
}

template<typename T>
typename std::enable_if<std::is_same<T, float>::value 
            || std::is_same<T, double>::value >::type Function(const T*in, T*out)
{
  Func3(in, out);
}