На самом деле, в C ++ 11 все стало намного проще благодаря decltype
и механизмам поздних привязок.
Теперь для проверки этого проще использовать методы:
// Culled by SFINAE if reserve does not exist or is not accessible
template <typename T>
constexpr auto has_reserve_method(T& t) -> decltype(t.reserve(0), bool()) {
return true;
}
// Used as fallback when SFINAE culls the template method
constexpr bool has_reserve_method(...) { return false; }
Затем вы можете использовать это в классе, например:
template <typename T, bool b>
struct Reserver {
static void apply(T& t, size_t n) { t.reserve(n); }
};
template <typename T>
struct Reserver <T, false> {
static void apply(T& t, size_t n) {}
};
И вы используете это так:
template <typename T>
bool reserve(T& t, size_t n) {
Reserver<T, has_reserve_method(t)>::apply(t, n);
return has_reserve_method(t);
}
Или вы можете выбрать enable_if
метод:
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<has_reserve_method(t), bool>::type {
t.reserve(n);
return true;
}
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<not has_reserve_method(t), bool>::type {
return false;
}
Обратите внимание, что это переключение вещей на самом деле не так просто. В целом, намного проще, когда существует только SFINAE - и вы просто хотите enable_if
один метод и не предоставлять какой-либо запасной вариант:
template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
t.reserve(n);
}
Если замена не удалась, этот метод удаляется из списка возможных перегрузок.
Примечание: благодаря семантике ,
(оператор запятой) вы можете объединять несколько выражений в decltype
, и только последнее фактически определяет тип. Удобно для проверки нескольких операций.