The code below works in gcc-4.8.2
#include <iostream>
using namespace std;
template<typename... Args>
void func(Args... args, int optional = 0)
{
cout << optional << endl;
}
int main()
{
func(1);
func(2.1f); // converts 2.1 to int as 'optional' parameter
func<float>(3.3f); // Fine, prints '0'
func(); // gcc OK, fails to compile with clang-3.5
}
And it outputs:
$ ./a.out
1
2
0
0
But if fails to compile with clang-3.5,
test_variadic.cpp:15:2: error: no matching function for call to 'func'
func();
^~~~
test_variadic.cpp:5:6: note: candidate function template not viable: requires at least argument 'args', but no arguments were provided
void func(Args... args, int optional = 0)
^
Clang at least warns of the implicit conversion from a float to an int. Fine, we can correct that by calling func<float>
which puts the float parameter into the template pack. So, if I comment out func()
, it compiles fine.
I can't find anything in the standard saying explicitly that variadic template pack has to be the last thing in the parameter-declaration-clause, just that it becomes a non-deduced context.
My confusion comes from why clang doesn't like func()
when func(1)
is perfectly acceptable. I can manually define func(int optional = 4) { cout << optional << endl; }
and everything is fine (but instead of the templated function when passing int
I correctly get the specialized func()
in both clang and gcc. What is clang enforcing that restricts the use of func()
?
This is actually covered by the slightly misplaced [temp.arg.explicit]/3:
A trailing template parameter pack (14.5.3) not otherwise deduced will be deduced to an empty sequence of template arguments.
The template parameter pack is trailing and thus deduced to the empty pack in all calls except for func<float>(3.3f)
, that is, they are all valid (and Clang compiles them fine as of 3.5).
However, the compilers are not conforming anymore once we adjust the template's declaration to
template <typename... Args, typename=void>
void func(Args... args, int optional = 0)
Now, the aforementioned quote is not applicable (as Args
is not trailing) and [temp.deduct.call]/1 applies instead:
When a function parameter pack appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced.
(I.e. this should yield a deduction failure.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With