invalid instantiation of template by compiler giving error

Viewed 44
#include<iostream>
template<typename T,  typename... Rest>
void printf_vt( const char *s, T value,Rest... rest)
{
    
 while (*s) {
    if (*s == '%' && *(++s) != '%') {
        std::cout << value;
        printf_vt(s, rest...); //called even when *s is 0,
        return; //but does nothing in that case
    }
    std::cout << *s++;
 }
}

int main() {
 int x = 10;
 float y = 3.6;
 const char* msg2 = "can accept % parameters (or %); x=%,y=%\n";
 printf_vt(msg2, 100, "more",x,y);
 return 0;
}

Program to imitate "C" printf function (not related to problem).

Error:

t1.cpp: In instantiation of 'void printf_vt(const char*, T, Rest ...) [with T = float; Rest = {}]':
t1.cpp:281:12:   recursively required from 'void printf_vt(const char*, T, Rest ...) [with T = const char*; Rest = {int, float}]'
t1.cpp:281:12:   required from 'void printf_vt(const char*, T, Rest ...) [with T = int; Rest = {const char*, int, float}]'
t1.cpp:293:11:   required from here
t1.cpp:281:26: error: no matching function for call to 'printf_vt(const char*&)'
  281 |                 printf_vt(s, rest...); //called even when *s is 0,
      |                 ~~~~~~~~~^~~~~~~~~~~~
t1.cpp:275:6: note: candidate: 'template<class T, class ... Rest> void printf_vt(const char*, T, Rest ...)'
  275 | void printf_vt( const char *s, T value,Rest... rest)
      |      ^~~~~~~~~
t1.cpp:275:6: note:   template argument deduction/substitution failed:
t1.cpp:281:26: note:   candidate expects at least 2 arguments, 1 provided
  281 |                 printf_vt(s, rest...); 
      |                 ~~~~~~~~~^~~~~~~~~~~~

The problem is compiler is trying to create template function using

Rest = {int , const char*, int , float}  //{100 , "more" , x , y}

Why it is doing so? When there are 2 required arguments compiler should not use 100 for variadic argument.

Will it also try to create template function with Rest = {const char* , int , const char* ,int , float}?

Is there any error with the code or that's not how variadic arguments are used?

Compiler g++ 11.1.0 (giving same error with clang too)

2 Answers

The problem is, at the final recursive call, rest becomes empty for printf_vt(s, rest...);; and there's no candidate printf_vt to be called.

You can add an overloaded printf_vt taking only const char * to match the above scenario, it's also expected to terminate the recursive call. E.g.

void printf_vt(const char *s)
{
    std::cout << s;
}

LIVE

You are missing a base case for the recursion in the template. The compiler is telling you that it cannot instantiate the template with Rest={}.

One way to provide a base-case is to have a no-Rest template as well. Add this template:

template<typename T>
void printf_vt( const char *s, T value)
{
 while (*s) {
    if (*s == '%' && *(++s) != '%') {
        std::cout << value << s;
        return;
    }
    std::cout << *s++;
 }
}

This doesn't recurse in the template parameters, and allows the test program to compile and run.

Related