Мне нравится использовать 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) { /* ... */ }
}
На практике я часто нахожу способность проверять условия на полезную способность.