Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic template, no matching function for call

I'm trying to use variadic template to refactor some of my code, but the compiler has "no matching function for call" error. Below is a simplified version (it may not make sense for functionality, but an example to reproduce the error):

// base case
void testFunc(int i) { std::cout << i << std::endl; }

template <class T, class... Args> void testFunc(int i) {
  T t = 0;
  std::cout << t << std::endl;
  testFunc<Args...>(i);
}

int main() {
  testFunc<int, long, float>(1);
  return 0;
}

The error messages:

main.cpp:9:3: error: no matching function for call to 'testFunc'
  testFunc<Args...>(i);
  ^~~~~~~~~~~~~~~~~
main.cpp:9:3: note: in instantiation of function template specialization 'testFunc<float>' requested here
main.cpp:9:3: note: in instantiation of function template specialization 'testFunc<long, float>' requested here
main.cpp:13:3: note: in instantiation of function template specialization 'testFunc<int, long, float>' requested here
  testFunc<int, long, float>(1);
  ^
main.cpp:6:40: note: candidate template ignored: couldn't infer template argument 'T'
template <class T, class... Args> void testFunc(int i) {
                                       ^
1 error generated.

It looks like that the unwrapping of template parameters is working, and stops at the base case. But I have defined the base case. Why there is no matching function?

like image 689
M. Yuan Avatar asked Mar 07 '23 02:03

M. Yuan


1 Answers

The problem is that calling

testFunc<Args...>(i);

you call the template version of testFunc(), not the base case version.

And when Args... is empty, there isn't a template version available.

To solve this problem... if you can use C++17, you can use if constexpr, as suggested by YSC.

For C++11 and C++14, I propose to use the template partial specialization of a struct.

The following is a full working example

#include <iostream>

// base case  
template <typename...>
struct foo
 { static void bar (int i) { std::cout << i << std::endl; } };

// recursive case
template <typename T, typename ... Args>
struct foo<T, Args...>
 {
   static void bar (int i)
    {
      std::cout << T{} << std::endl;

      foo<Args...>::bar(i);
    }
 };

int main()
 {
   foo<int, long, float>::bar(1);
 }
like image 167
max66 Avatar answered Mar 14 '23 14:03

max66