Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a parameter pack allowed after default arguments?

Tags:

Maybe I'm missing something obvious, but the following compiles and runs, and I'm not sure why. I am aware of this, but in the example below the position of the parameter pack and the default argument are reversed. Doesn't it violate the rule that default arguments have to appear last? The parameter pack cannot have a default value.

#include <iostream>
#include <string>
#include <tuple>

template<typename ... Ts>
struct Test
{
    int i;
    std::string str;

    Test(int _i = 0, Ts&& ... _ts)
        :
          i(_i),
          str(std::get<0>(std::forward_as_tuple(std::forward<Ts>(_ts)...)))
    {}
};

int main()
{
    Test<std::string> t(1, "huh??");
    std::cout << "t.i = " << t.i << ", t.str = " << t.str << "\n";

    return 0;
}

This produces

t.i = 1, t.str = huh??
like image 270
cantordust Avatar asked Nov 16 '17 13:11

cantordust


3 Answers

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

For non-template functions, default arguments can be added in later declarations of a function in the same scope. Declarations in different scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa. 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. A default argument shall not be redefined by a later declaration (not even to the same value). [ Example:

void g(int = 0, ...); // OK, ellipsis is not a parameter. So it can follow a parameter with a default argument 
like image 160
msc Avatar answered Oct 30 '22 15:10

msc


As an addition to the great answer by rsp, it's also worth noting that this behavior makes logical sense. Non-default, non-parameter-pack arguments cannot follow a default argument without resulting the in the requirement that the default argument has to be specified--in which case it is no longer a default argument.

For example, if the following were allowed:

void example(int x=0, int y); 

The non-default second argument would mean a call to function would need to be structured example(1, 2); as the first parameter cannot be defaulted. This is not the case for an empty parameter pack. Consider the following function:

template <typename... T> void example(int x = 0, T&&... t); 

In this case it is still possible to default x by calling example();

like image 21
AzCopey Avatar answered Oct 30 '22 16:10

AzCopey


The why of it is simple. Effectively parameter packs always have a default: Parameter packs can be empty, so that won't contradict the concept that missing defaults must be the last arguments.

like image 26
Gem Taylor Avatar answered Oct 30 '22 14:10

Gem Taylor