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.
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.