Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang vs GCC - Variadic template parameter pack followed by parameter with default value works in GCC 4.8 but not Clang 3.5

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()?

like image 653
ilektron Avatar asked Dec 04 '14 20:12

ilektron


1 Answers

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.)

like image 143
Columbo Avatar answered Nov 20 '22 16:11

Columbo