Мне нравится использовать SFINAE
для проверки логических условий.
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 */
}
Это может быть весьма полезно. Например, я использовал его, чтобы проверить, является ли список инициализатора, собранный с помощью запятой оператора, не длиннее фиксированного размера
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i, char(*)[M <= N] = 0) { /* ... */ }
}
Список принимается, только когда M меньше N, что означает, что в списке инициализатора не слишком много элементов.
Синтаксис char(*)[C]
означает: Указатель на массив с типом элемента char и размером C
. Если C
равно false (здесь 0), то мы получим недопустимый тип char(*)[0]
, указатель на массив нулевого размера: SFINAE делает так, что шаблон будет игнорироваться.
Выражается boost::enable_if
, это выглядит так
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i,
typename enable_if_c<(M <= N)>::type* = 0) { /* ... */ }
}
На практике я часто нахожу способность проверять условия полезной способностью.