Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this function template call work?

The following code compiles:

template<int...>
struct Indices {};

template<int J, int ...I>
void foo(Indices<I...>) {}

int main(int argc, char **argv)
{
  foo<2>(Indices<3,4,5>()); //why does this work?
  return 0;
}

In the function call, it seems to me that the J parameter becomes 2 and the ...I parameter becomes 3,4,5?

But why does this work? I only specified 2 at foo<2> meaning I specified J as 2 and ...I as nothing. Why can I still specify ...I through the Indices argument? What template mechanism is being used here?

Update: The current answer does not explain why I can have one argument not deduced (explicitly specified) but the others deduced. When exactly does this work? I hope I'm not relying on undefined behavior. Does the standard allow what I'm doing above?

like image 996
roger.james Avatar asked Jun 03 '26 23:06

roger.james


1 Answers

The parameter unpack ...I is deduced by the compiler from the function argument. It is called template argument deduction.

Here are some simple, yet useful examples:

template<typename T> 
void f(T const&) {}

f(10);   //T is deduced as int
f(10.0); //T is deduced as double
f("10"); //T is deduced as char[3]

Many functions from the standard library are function template, and often the template argument is deduced. Here is one example:

std::vector<int> vi;
std::vector<std::string> vs;
//...
std::sort(vi.begin(), vi.end()); //template argument deduction
std::sort(vs.begin(), vs.end()); //template argument deduction

Here std::sort is a function template but as you can see, we don't explicitly pass the template argument. It is because the template argument is deduced by compiler itself, from the function arguments.

Hope that helps.

like image 177
Nawaz Avatar answered Jun 06 '26 11:06

Nawaz