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