为什么在默认参数之后允许参数包?

Why is a parameter pack allowed after default arguments?

也许我遗漏了一些明显的东西,但以下编译并运行,我不确定为什么。我知道 this,但在下面的示例中,参数包和默认参数的位置颠倒了。这不违反默认参数必须最后出现的规则吗?参数包不能有默认值。

#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;
}

这会产生

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

作为对 rsp 出色回答的补充,还值得注意的是,这种行为是合乎逻辑的。非默认、非参数包参数不能跟在默认参数之后,除非导致必须指定默认参数的要求——在这种情况下,它不再是默认参数。

例如,如果允许以下情况:

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

非默认的第二个参数意味着调用函数需要结构化example(1, 2);,因为第一个参数不能默认。这不是空参数包的情况。考虑以下函数:

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

在这种情况下,仍然可以通过调用 example();

默认值 x

原因很简单。实际上参数包总是有一个默认值:参数包可以是空的,这样就不会与缺少默认值必须是最后一个参数的概念相矛盾。