SFINAE je princip koji omogućava preopterećenje predložaka funkcija ali ujedno i
neke specifične tehnike programiranja. Princip se sastoji u sljedećem:
Kada prevodilac pokušava
instancirati funkciju iz više preopterećenih predložaka supstitucija parametra u neke od predložaka
dovodi do neuspjeha. Taj neuspjeh nije grešaka već prevodilac nastavlja sa sljedećim predloškom,
dok ne uspije instancirati traženu funkciju.
Primjena: identificiramo da li zadani tip ima podtip X
.
typedef char RT1;
typedef struct{ char a[2]; } RT2;
Zatim definiramo dva predloška funkcije: prvi uzima pokazivač na konstantan podtip X
dok drugi uzima sve vrste argumenta (...
) — to je C-verzija funkcije s proizvoljnim brojem argumenataza korištenje
vidi www.cplusplus.com/reference/cstdarg/.
template <typename T> RT1 test(typename T::X const*);
template <typename T> RT2 test(...);
Definirajmo jedan tip koji ima podtip X
.
struct VVV{
typedef int X;
// ..
};
int main()
{
std::cout << sizeof(test<VVV>(0)) << std::endl; // ispisuje 1
std::cout << sizeof(test<double>(0)) << std::endl; // ispisuje 2
return 0;
}
Kod funkcionira na sljedeći način:
-
prevodilac treba odabrati koji će funkcijski predložak instancirati
na osnovu parametra (
0
) koji je tipa const int
.
-
Takav se parametar može konvertirati u
pokazivač na
const T::X
(naravno kao tip T
ima podtip X
).
-
Ta konverzija je slabija od
konverzije koja je potrebna za funkciju koja uzima proizvoljne parametre (
...
).
To znači da će
prevodilac preferirati test
koji vraća RT1
ukoliko T
ima podtip X
.
Time smo dobili tehniku kojom možemo provjeriti (za vrijeme kompilacije) da li neki tip
ima podtip X
(sizeof
daje 1) ili nema (sizeof
daje 2).
Kao sljedeći korak možemo definirati makro:
#define type_has_memeber_type_X(T) \
(sizeof(test<T>(0)) == 1)
i koristiti ga na sljedeći način,
type_has_memeber_type_X(double); // daje 0=false
type_has_memeber_type_X(VVV); // daje 1=true