Home > Net >  Deduction in template functions with few args
Deduction in template functions with few args

Time:06-27

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.

CodePudding user response:

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

CodePudding user response:

The lambdas are of different types. You need to add another template parameter for the second one:

#include <type_traits> // for the proper `std::invocable`

template <class Task, class AnotherTask>
void doTasks(Task task1, AnotherTask task2) {
    if constexpr (std::is_invocable_v<Task> && std::is_invocable_v<AnotherTask>) {
        std::cout << "doing first task\n";
        task1();
        std::cout << "doing second task\n";
        task2();
    }
}

Note: Since it's C 17, you can also use constexpr if to deal with the if at compile time only.

Demo

  • Related