Search code examples
c++templatesoverloadingvariadic-templatessfinae

Enable template if functor passed as argument takes no argument


I am trying to define two overload for a template function. First overload is generated if functor passed as an argument has no parameter otherwise second overload is generated. I started to implement like this :

template <typename R, typename... Types>
constexpr size_t argumentCount(R (*f)(Types...))
{
    return sizeof...(Types);
}

template <typename Function>
typename std::enable_if<argumentCount<Function>() == 0, int>::value = 0 > callFunc(Function fu)
{
    fu();
}

template <typename Function, typename... Params>
typename std::enable_if<argumentCount<Function>() == 0, int>::value = 0 > callFunc(Function fu, Params... params)
{
    fu(std::forward<decltype(params)>(params)...);
}

This does not compile for several reasons including parse error.What I want to do is,

callFunc([](){}); will call overload 1 while callFunc([](int value1,int value2){}); will call overload 2.

How can I achieve this ?


Solution

  • If you can add a level of indirection... what about using tag-dispatching instead of SFINAE?

    I mean, something as follows

    #include <iostream>
    #include <type_traits>
    
    template <typename F>
    void callFunc_helper (F fu, std::true_type)
     {
       std::cout << "zero version" << std::endl;
    
       fu();
     }
    
    template <typename F, typename... Prs>
    void callFunc_helper (F fu, std::false_type, Prs && ... params)
     {
       std::cout << "non zero version" << std::endl;
    
       fu(std::forward<Prs>(params)...);
     }
    
    template <typename F, typename... Prs>
    void callFunc (F fu, Prs && ... params)
     { callFunc_helper(fu, std::integral_constant<bool, 0u == sizeof...(Prs)>{},
                       std::forward<Prs>(params)...); }
    
    int main ()
     {
       callFunc([]{});
       callFunc([](int, int){}, 0, 1);
     }
    

    Obviously you can use std::integral_constant<bool, 0u == argumentCount<Function>()>{} if you really want to check the number of the functional arguments instead of the number of the following parameters (but why?).