In https://stackoverflow.com/a/1967183/134841, a solution is provided for statically checking whether a member exists, possibly in a subclass of a type:
template <typename Type>
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 <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
However, it doesn't work on C++11 final
classes, because it inherits from the class under test, which final
prevents.
OTOH, this one:
template <typename C>
struct has_reserve_method {
private:
struct No {};
struct Yes { No no[2]; };
template <typename T, typename I, void(T::*)(I) > struct sfinae {};
template <typename T> static No check( ... );
template <typename T> static Yes check( sfinae<T,int, &T::reserve> * );
template <typename T> static Yes check( sfinae<T,size_t,&T::reserve> * );
public:
static const bool value = sizeof( check<C>(0) ) == sizeof( Yes ) ;
};
fails to find the reserve(int/size_t)
method in baseclasses.
Is there an implementation of this metafunction that both finds reserved()
in baseclasses of T
and still works if T
is final
?
A version that also relies on
decltype
but not on passing arbitrary types to(...)
[ which is in fact a non-issue anyway, see Johannes' comment ]:I'd like to point out according to this trait a type such as
std::vector<int>&
does supportreserve
: here expressions are inspected, not types. The question that this trait answers is "Given an lvaluelval
for such a typeT
, is the expressionslval.reserve(0);
well formed". Not identical to the question "Does this type or any of its base types has areserve
member declared".On the other hand, arguably that's a feature! Remember that the new C++11 trait are of the style
is_default_constructible
, nothas_default_constructor
. The distinction is subtle but has merits. (Finding a better fitting name in the style ofis_*ible
left as an exercise.)In any case you can still use a trait such as
std::is_class
to possibly achieve what you want.Actually, things got much easier in C++11 thanks to the
decltype
and late return bindings machinery.Now, it's just simpler to use methods to test this:
You can then use this in a class for example:
And you use it so:
Or you can choose a
enable_if
method:Note that this switching things is actually not so easy. In general, it's much easier when just SFINAE exist -- and you just want to
enable_if
one method and not provide any fallback:If substitution fails, this method is removed from the list of possible overloads.
Note: thanks to the semantics of
,
(the comma operator) you can chain multiple expressions indecltype
and only the last actually decides the type. Handy to check multiple operations.