I want to get into more template meta-programming. I know that SFINAE stands for "substitution failure is not an error." But can someone show me a good use for SFINAE?
I like using SFINAE
to check boolean conditions.
template<int I> void div(char(*)[I % 2 == 0] = 0) {
/* this is taken when I is even */
}
template<int I> void div(char(*)[I % 2 == 1] = 0) {
/* this is taken when I is odd */
}
It can be quite useful. For example, i used it to check whether an initializer list collected using operator comma is no longer than a fixed size
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i, char(*)[M <= N] = 0) { /* ... */ }
}
The list is only accepted when M is smaller than N, which means that the initializer list has not too many elements.
The syntax char(*)[C]
means: Pointer to an array with element type char and size C
. If C
is false (0 here), then we get the invalid type char(*)[0]
, pointer to a zero sized array: SFINAE makes it so that the template will be ignored then.
Expressed with boost::enable_if
, that looks like this
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i,
typename enable_if_c<(M <= N)>::type* = 0) { /* ... */ }
}
In practice, i often find the ability to check conditions a useful ability.