has_member

Does T have a member function foo(int)?

There are a few cases where you want to check if some type has a member function with a given name and signature. In this article, I will present an easy-to-use framework for making your own member checkers. First, I will present a non-generic checker so I can explain how and why it works. Then, I will present a generic checker which uses the same techniques to make a system which is easy to use with your own types and function signatures.

The goal of this article is a type where has_foo<T>::value will evaluate to true if the type T has a function foo and false if it does not.

A “Simple” Example

To make things a little less painful, let’s start with a type which can only check for a single function. In this class, we check that there is a void T::foo(int).

template <typename T>
class has_foo
{
private:
    template <typename U, U>
    class check
    { };

    template <typename C>
    static char f(check<void (C::*)(int), &C::foo>*);

    template <typename C>
    static long f(...);

public:
    static const bool value = (sizeof(f<T>(0)) == sizeof(char));
};

Okay, so that looks a little funny, but stick with me for a bit.

Example: A False Case

Let’s step through this when the compiler instantiates the template, starting with a class which does not have a foo(int).

struct No
{ };

The only thing defined is value, which contains the interesting subexpression sizeof(f<T>(0)). This means to get the size of the return type for the given subexpression (f<T>(0)). In this class, there are two functions with the name f, so the question is: Which f would f<T>(0) call? To find out, the compiler finds template functions named f. One such f is:

template <typename C>
static char f(check<void (C::*)(int), &C::foo>*);

This f is looking for a pointer to some funny-looking template class check. Now, the first template parameter names a type: void (C::*)(int) – a pointer to a member function on C which takes an int and returns void. The compiler is happy with this first parameter, because there could be a function like that. The second template parameter &C::foo selects the function foo on C. Uh-oh: No, the provided C, does not have a function named foo and the compiler has a substitution failure. However, substitution failure is not an error comes to the rescue. Instead of breaking and giving you a 100-line error message, this failed substitution means template <typename C> static char f(check<void (C::*)(int), &C::foo>*) is just thrown out.

The remaining candidate for overload resolution is template <typename C> static long f(...), which is not terribly interesting. The ... takes any type of argument, so it will work just fine for f<T>(0). The return type of this function is long, leaving value = (sizeof(long) == sizeof(char)). Ultimately, this yields value = false and everything is good to go.

Example: A True Case

What does the compiler do on a class which has the correct void foo(int)?

struct Yes
{
    void foo(int x);
};

Let’s start with the place where the false case had a substitution failure.

template <typename C>
static char f(check<void (C::*)(int), &C::foo>*);

Unlike before, the expression &C::foo is valid and we have a function which is looking for a pointer to the check object. The function template <typename C> static char f(...) is, of course, still under consideration, which means the compiler has found two possible f:

  • char f(check*)
  • long f(...)

The compiler must now decide which f you meant to call with the expression f<T>(0), so it evaluates the possible types for the parameters. Can the argument 0 be a check*? Yes! 0 is the null pointer. Likewise, 0 can be the single parameter to the varargs f(...). Luckily enough, this does not mean that f<T>(0) is ambiguous. Interpreting 0 as the null pointer is more specific than interpreting it as an argument in a varargs list (in fact, almost anything is more specific), so the compiler will see f<T>(0) as a call to template <typename C> static char f(check<void (C::*)(int), &C::foo>*).

The return type of the function is char, leaving value = (sizeof(char) == sizeof(char)), making ``value = true.

Example: The Wrong Type

What about a class which has a function named foo, but with the wrong signature?

struct Wrong
{
    void foo(double x);
};

Here, the definition of check comes into play.

template <typename U, U>
class check
{ };

The type for the first template parameter U will be void (Wrong::*)(int). The second template parameter expects some U, which the signature of f demands it be &C::foo. However, &Wrong::foo is a void (Wrong::*)(double), which leads to a substitution failure.

Real Implementation: Checker Class

While has_foo certainly works, making another class has_bar or has_baz would require a bit of copy and paste work. The definition of the signature and name of the member function is sibling to the strange-looking logic of SFINAE. Without documentation, it is not obvious what this class is even used for or how it works. Ideally, we should be able to define new checkers more like this:

template <typename T>
struct has_foo : has_member<T, check_has_foo>
{ };

It can be done!

#include <type_traits>

namespace detail
{

template <typename T, typename NameGetter>
struct has_member_impl
{
    typedef char matched_return_type;
    typedef long unmatched_return_type;

    template <typename C>
    static matched_return_type f(typename NameGetter::template get<C>*);

    template <typename C>
    static unmatched_return_type f(...);

public:
    static const bool value = (sizeof(f<T>(0)) == sizeof(matched_return_type));
};

}

template <typename T, typename NameGetter>
struct has_member :
        std::integral_constant<bool, detail::has_member_impl<T, NameGetter>::value>
{ };

The has_member_impl class looks similar to the has_foo class. The has_member class gives us a way to make std::true_type and std::false_type. The big technical difference is to the matcher: template <typename C> static matched_return_type f(typename NameGetter::template get<C>*). (<a href=”#info-typename-template”>4</a>). This pushes responsibility of matching <tt>T</tt> outside of the class and into the new type parameter <tt>NameGetter</tt>.

Note

What’s with ``typename NameGetter::template get<C>``?

The typename is needed here because we are using NameGetter dependent context, which is a fairly common thing to see. The less common thing to see is the extra template before get. If that is not there, g++ gives you error: non-template 'get' used as template along with the friendly note: use 'NameGetter::template get' to indicate that it is a template. It is fairly easy for a human to look at this code and say: Clearly, my check_print::get is a template, the compiler is stupid! However, when you say typename NameGetter::get, you are explicitly telling the compiler that NameGetter::get names a type, not that it names a templated type.

A NameGetter might look something like this:

struct check_has_foo
{
    template <typename T,
              void (T::*)(int) = &T::foo
             >
    struct get
    { };
};

Now, the responsibility of checking the function signature is in it’s own class. This separation of data and logic makes for easy reuse. If we wanted to check for a function bar which took two float, returned an int and operated on const T, we could do that:

struct check_has_bar
{
    template <typename T,
              int (T::*)(float, float) const = &T::bar
             >
    struct get
    { };
};

template <typename T>
struct has_bar : has_member<T, check_has_bar>
{ };

The interesting thing is that there is no requirement that we only check for one function. In fact, it is quite easy to check for a number of functions:

struct check_read_write
{
    template <typename T,
              int (T::*)() const = &T::read,
              void (T::*)(int) = &T::write
             >
    struct get
    { };
};

template <typename T>
struct has_bar : has_member<T, check_has_bar>
{ };

Real-World Use

Let’s say you wanted to overload operator<< to call the print function on a bunch of objects (which can be useful when you want to print polymorphically). You can not just write a function like this:

template <typename T>
std::ostream& operator<<(std::ostream& stream, const T& value)
{
    value.print(stream);
    return stream;
}

The problem is that every type would match against that function definition, including types like int, which will fail marvelously inside the function. What you need is a way to enable operator<< only for types which have your print function. Luckily, we have std::enable_if! First, let’s define the class which checks for the print function.

struct check_has_print
{
    template <typename T,
              void (T::*)(std::ostream&) const = &T::print
             >
    struct get
    { };
};

template <typename T>
struct has_print :
        has_member<T, check_has_print>
{ };

Now, we can use the checker with enable_if:

template <typename T>
typename std::enable_if<has_print<T>::value, std::ostream&>::type
operator<<(std::ostream& stream, const T& value)
{
    value.print(stream);
    return stream;
}

This works under the same principles of substitution failure is not an error. When the first value is false, the member type is not defined, causing substitution failure on the overload for that type. We have to hack this check into the return type, since operator<< only accepts two parameters.

More Info

Source Code

Get the source code for the has_member class here: has_member.hpp. It is Apache licensed, so use it under those terms (just drop the header into your code). There is also a demo program: has_member.cpp. It has been compiled and tested with g++ 4.6.2, but any compiler with the <type_traits> library should be perfectly fine with it (or you can change it to use Boost’s Type Traits library).