29

This is a point about which gcc 4.9.2 and clang 3.5.2 are in sharp disagreement. The program:

template<typename ...Ts>
int foo(int i = 0, Ts &&... args)
{
    return i + sizeof...(Ts);
}

int main()
{
    return foo();
}

compiles without comment from gcc (-std=c++11 -Wall -pedantic). Clang says:

error: missing default argument on parameter 'args'

With foo amended to:

template<typename ...Ts>
int foo(int i = 0, Ts &&... args = 0)
{
    return i + sizeof...(Ts);
}

clang has no complaints, but gcc says:

error: parameter pack ‘args’ cannot have a default argument

Which compiler is right?

T.C.
  • 133,968
  • 17
  • 288
  • 421
Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • 1
    You could work around it by overloading: `template int foo(int i, Ts&&...) { return i + sizeof...(Ts); } inline int foo() { return foo(0); }` – Oktalist Mar 17 '15 at 22:00

2 Answers2

27

From 8.3.6 ([dcl.fct.default])/3:

A default argument shall not be specified for a parameter pack.

From 8.3.6 ([dcl.fct.default])/4:

In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration or shall be a function parameter pack.

So this allows code like void f(int a = 10, Args ... args), or indeed like your first snippet. (Thanks to @T.C. for looking up the second sentence!)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 3
    [dcl.fct.default]/4 ("In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration or shall be a function parameter pack.") would appear to permit the first version. – T.C. Mar 17 '15 at 18:45
  • @KerrekSB Yes, so it permits the version accepted by GCC. – T.C. Mar 17 '15 at 20:31
  • @T.C.: Yes, thanks, I've absorbed that into the post if you don't mind :-) – Kerrek SB Mar 17 '15 at 21:21
  • 1
    clang bugs filed: [23028](https://llvm.org/bugs/show_bug.cgi?id=23028) [23029](https://llvm.org/bugs/show_bug.cgi?id=23029) – Oktalist Mar 26 '15 at 00:01
  • Fixed in trunk, so will be fixed in the next release of clang. That was quick! – Oktalist Mar 27 '15 at 16:52
6

A Kerrek SB says, it's not possible. What you could do, instead, is using a std::tuple

template <class ... Args>
void foo( std::tuple<Args...> t = std::tuple<int>(0) )
{}
edmz
  • 8,220
  • 2
  • 26
  • 45