C++ Member Function Detector Macro

In C++, we often use the substitution failure is not an error (SFINAE) rule in template overload resolution. A common problem is to write template specializations for class template arguments that expose member functions with a certain signature. The below macro allows to easily create member function detector type traits for user defined classes

#include <type_traits>

#define MEMBER_FUNCTION_DETECTOR(DetectorName, FunctionName, ReturnType, ...)                           \
    template<typename T>                                                                                \
    struct DetectorName                                                                                 \
    {                                                                                                   \
        /*                                                                                              \
         * \brief The second argument must be the return type of the first. We need to                  \
         *        implement two versions of the test - one for non-const and one for                    \
         *        const member functions.                                                               \
         */                                                                                             \
        template<typename U, U u> class Checker;                                                        \
                                                                                                        \
        template<typename V>                                                                            \
        static std::true_type test(Checker<ReturnType (V::*)(__VA_ARGS__), &V::FunctionName> *);        \
                                                                                                        \
        template<typename V>                                                                            \
        static std::true_type test(Checker<ReturnType (V::*)(__VA_ARGS__) const, &V::FunctionName> *);  \
                                                                                                        \
        template<typename V>                                                                            \
        static std::false_type test(...);                                                               \
                                                                                                        \
        typedef decltype(test<T>(nullptr)) type;                                                        \
        static const bool value = std::is_same<std::true_type, type>::value;                            \
    };

The macro creates a templated detector struct DetectorName<T> that allows us to check whether a function with the signature ReturnType T::FunctionName(...) exists. The variable macro arguments correspond to the function’s parameter types. The following snippet demonstrates the usage.

struct A
{
    bool foo(double x);
}

MEMBER_FUNCTION_DETECTOR(FooDetector, foo, bool, double)

int main() {
    static_assert(FooDetector<A>::value, "Foo not implemented.");
}

Leave a Reply

Your email address will not be published. Required fields are marked *