In fact, everything has become much simpler in C ++ 11 thanks to decltype and late return bindings binding mechanisms.
Now itβs just easier to use methods to verify this:
// 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; }
Then you can use this in a class, for example:
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) {} };
And you use it like this:
template <typename T> bool reserve(T& t, size_t n) { Reserver<T, has_reserve_method(t)>::apply(t, n); return has_reserve_method(t); }
Or you can choose the enable_if method:
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; }
Note that this switch is actually not that simple. In general, it is much simpler when only SFINAE exists - and you just want to enable_if one method and not provide any backup:
template <typename T> auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) { t.reserve(n); }
If substitution fails, this method is removed from the list of possible overloads.
Note: thanks to semantics , (comma operator) you can bind multiple expressions in decltype , and only the latter actually solves the type. It is convenient to check multiple operations.