В https://stackoverflow.com/a/1967183/134841 предоставляется решение для статической проверки того, является ли член существует, возможно, в подклассе типа:
template
class has_resize_method
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void resize(int){}
};
struct Base : public Type, public BaseMixin {};
template class Helper{};
template
static no deduce(U*, Helper* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
Однако он не работает с классами C ++ 11 final
, поскольку наследуется от тестируемого класса, который final
] предотвращает.
OTOH, этот:
template
struct has_reserve_method {
private:
struct No {};
struct Yes { No no[2]; };
template struct sfinae {};
template static No check( ... );
template static Yes check( sfinae * );
template static Yes check( sfinae * );
public:
static const bool value = sizeof( check(0) ) == sizeof( Yes ) ;
};
не удается найти метод резерв (int / size_t)
в базовых классах.
Существует ли реализация этой метафункции, которая находит reserved ()
в базовых классах T
и по-прежнему работает, если T
является final
]?
На самом деле, все стало намного проще в 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
, и только последнее фактически решает тип. Удобно для проверки нескольких операций.