Search code examples
c++templatesc++17template-argument-deductionfunction-templates

Deduction in template functions with few args


I have few instances of one template function. Each of them sequentially executes each of given lambdas, accompanying them with specific messages. When I do that with one lambda, everything works fine, but when I try to add more than one, I get

note: candidate template ignored: deduced conflicting types for parameter 'Task'

From clang. Here is my code:


template <class Task> void doTasks(Task task1)  // works fine
{  
    if (std::__is_invocable<Task>::value) 
    {
        std::cout << "doing first task" << endl;
        task1;
    }
}

template <class Task>
void doTasks(Task task1, Task task2) // deduced conflicting types
{ 
    if (std::__is_invocable<Task>::value) 
    {
        std::cout << "doing first task" << endl;
        task1();
        std::cout << "doing second task" << endl;
        task2();
    }
}


int main()
{
    doTasks([&] (){std::cout << "1" << endl;}); 

    doTasks([&] (){std::cout << "1" << endl;},
            [&] (){std::cout << "2" << endl;}); 
  
    return 0; 
}

What's wrong with it? How can I deal with my problem?

Sorry if it's a stupid question, I'm some kind of beginner in C++ and may not understand some template nuances.


Solution

  • Even though the two passed lambdas does the same or looks similar, they have completely different types. Hence, you need two different template types there in the doTasks.

    Easy fix is providing the template parameter for two lambdas

    template <class T1, class T2>
    void doTasks(T1 task1, T2 task2)
    {
      // ...
    }
    

    otherwise, using the variadic template function and fold expression, you could do something like:

    #include <type_traits> // std::conjunction_v, std::is_invocable
    
    template <class... Ts>
    void doTasks(Ts&&... lmds) {
        if (std::conjunction_v<std::is_invocable<Ts>...>) // maybe if constexpr
        {
            (lmds(), ...);
        }
    }
    

    Since the argument is variadic, it will also work for the single/ any arguments of doTasks and hence no code duplication.

    Live demo