Search code examples
c++11variadic-templatesvariadic-functionssfinae

Compile time existence checking for a member function with signature fit to variadic parameters pack


I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.

I try to do something like this:

// Note: T object may have several functions with the name foo, but with different signatures.
//       a function foo also can be a template one with variadic parameters pack.
       
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
    template<typename U>
    static bool test(decltype(&U::foo));

    template<typename U>
    static float test(...);

public:
    static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;

    //-------------------------------------------------------------^^^^^^^^^
    // how to do it? 

};

I would like to use it for declaring specific object at compile time - something like this:

class Bar
{
public:
    template<typename T, typename...Args>
    void doSomthing(T* p, Args&&...parameters)
    {
        // get correct object type:
        // if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
        using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;

        // compute
        ObjType::doSomthing(p, std::forward<Args>(parameters)...);
    }

private:
    struct A
    {
        template<typename T, typename...Args>
        static void doSomthing(T* p, Args&&...parameters)
        {
            p->foo(std::forward<Args>(parameters)...);
        }
    };

    struct B
    {
        template<typename T, typename...Args>
        static void doSomthing(T* p, Args&&...parameters)
        {
            // do something else
        }
    };

};

Solution

  • Something like this, perhaps:

    template<typename T, typename...Args>
    class HAS_FUNCTION_FOO
    {
        template <typename U>
        static std::true_type test(
            typename std::enable_if<sizeof(
                decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
        );
    
        template <typename U>
        static std::false_type test(...);
    
    public:
        static constexpr bool value = decltype(test<T>(nullptr))::value;
    };
    

    Demo