3

The following code implements a function template foo that accepts an arbitrary number of arguments, and subsequently handles each one while maintaining a positional index of that argument:

template<int index, typename T>
void foo_impl(T value)
{
    // Do something with index/value
}

template<int index, typename T, typename... Rest>
void foo_impl(T value, Rest... values)
{
    // Do something with index/value
    // Recursively handle remaining arguments
    foo_impl<index + 1>(values...);
}

template<typename... T>
void foo(T... args)
{
    foo_impl<1>(args...);
}

int main()
{
    foo("test", 42);
}

This recursively instantiates function templates until it reaches the base template that takes a single argument. Every function template instantiation of foo_impl omits the template type arguments. Although this compiles with Clang, GCC, and MSVC, I'm not sure this is legal.

Is it legal to omit the template arguments as illustrated in the code example? If so, what are the specific rules? And have those rules changed between C++ Standards?

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • 2
    When you say omit template arguments are you referring to the `foo("test", 42)` line? You don't need explicit template arguments because the compiler deduces the types. – David G Mar 09 '20 at 15:40
  • 2
    The term of art is [template argument deduction](https://en.cppreference.com/w/cpp/language/template_argument_deduction) – Igor Tandetnik Mar 09 '20 at 15:42
  • 1
    Does this answer your question? [Partial template function specification in C++ works, but why?](https://stackoverflow.com/questions/13554496/partial-template-function-specification-in-c-works-but-why) – Al.G. Mar 11 '20 at 11:08
  • @al.g: It does, however the answer on that other question is just a lot less complete than the answer here, so I'm hesitant to close it as a duplicate. – IInspectable Mar 11 '20 at 11:12
  • Hmm, you're right; and it also doesn't say anything about parameter packs. – Al.G. Mar 11 '20 at 11:20

1 Answers1

6

The specific rule is in [temp.arg.explicit]

3 Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted. In contexts where deduction is done and fails, or in contexts where deduction is not done, if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.

Since the type arguments are trailing, and can be deduced from the arguments of the function call, they may be omitted.

Such verbiage exists in all standard revisions to date (except for the bit about parameter packs, which isn't there in C++03).

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458