Listings Wilkening/SFINAE


Listing 1: Den Code um ein Funktionstemplate erweitern
void fct(int);
void fct(double);
void fct(const string&);

template<class T> void fct(T); 
template<class T> void fct(typename T::type);

fct(42);
fct(true);

--------

Listing 2: Funktionstemplate über explizite Typdeduktion anwenden
void fct(int);
void fct(double);
void fct(const string&);

template<class T> void fct(T); 
template<class T> void fct(typename T::type);

struct A
{
    using type = bool;
};

fct(42);
fct(true);
fct<A>(true);    // => Funktionstemplate mit T==A => fct<A>(bool)

--------

Listing 3: Fehler in der Implementierung als Ausnahme
// Beispiel 1
void fct(int);
void fct(double);
void fct(const string&);

template<class T> typename T::type fct(T);    // SFINAE im Rueckgabetyp - okay

// Beispiel 2
void fct(int);
void fct(double);
void fct(const string&);

template<class T> void fct(T)
{
    typename T::type x;    // Implementierung => kein SFINAE => Compilerfehler
}

--------

Listing 4: Ellipsenfunktion wandeln
// Beispiel 1
void fct(...);
template<class T> void fct(typename T::type);

struct A
{
    using type = int;
};

fct(42);    // => Ellipsen-Funktion
fct<A>(42);  // => T::type

// Beispiel 2
template<class> void fct(...);
template<class T> void fct(typename T::type);

struct A 
{ 
    using type = int;
};

fct<int>(42);   // => Ellipsenfunktion
fct<A>(42);     // => T::type

--------

Listing 5: Pseudocode zur init-Funktion
// Pseudocode, KEIN C++-Code
template<class T> T* create()
{
    T* res = new T();
    if (T has-init-member-function)    // (*)
    {
       res->init();    // (**)
    }
    return res;
}

--------

Listing 6: SFINAE-Mechanismus mit Ellipsenfunktion
// Teil 1
template<typename T> struct HasInitFct
{
    using Yes = char[1];
    using No = char[2];

    template<typename U, U> struct SignatureCheck;

    template<typename V> static Yes& check(SignatureCheck<void(T::*)(), &V::init>*);
    template<typename>   static No&  check(...);

    static bool const value = sizeof(check<T>(nullptr)) == 1;
};

// Teil 2
struct NoInit
{
};

struct WithInit
{
    void init() {}
};

static_assert(!HasInitFct<NoInit>::value);
static_assert(HasInitFct<WithInit>::value);

cout << boolalpha;
cout << "NoInit   -> " << HasInitFct<NoInit>::value << endl;    // => false
cout << "WithInit -> " << HasInitFct<WithInit>::value << endl;    // => true

--------

Listing 7: Member Checker zur Typunterscheidung
struct InitNo
{
    template<class T> static void init(T&)
    {
    }
};

struct InitYes
{
    template<class T> static void init(T& t)
    {
      t.init();
    }
};

template<class T> void init(T& t)
{
    using Type = conditional_t<HasInitFct<T>::value, InitYes, InitNo>;
    Type::init(t);
}

NoInit obj_no;
init(obj_no);    // => Kein Aufruf von "init"

WithInit obj_yes;
init(obj_yes);    // => Aufruf von "init"

--------

Listing 8: Problemloses Resetten von PODs und Non-PODs

struct PodType
{
    long long ll1, ll2;
};

struct NonPodType
{
    string s1, s2;

    void reset()
    {
      s1 = s2 = ""s;
    }
};

PodType pt;
reset(pt);    // Ruft die Reset-Funktion fuer POD-Typen auf

NonPodType npt;
reset(npt);    // Ruft die Reset-Funktion fuer Non-POD-Typen auf

--------

Listing 9: SFINAE für die Signatur
template<class T> void reset(T& t, enable_if_t<is_pod_v<T>, T*> = nullptr)
{
    memset(&t, 0, sizeof(T));
}

template<class T> void reset(T& t, enable_if_t<!is_pod_v<T>, T*> = nullptr)
{
    t.reset();
}

--------

