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

can*_*ust 19 c++ default-arguments c++11 c++14

也许我错过了一些明显的东西,但是下面的编译和运行,我不知道为什么.我知道这一点,但在下面的示例中,参数包的位置和默认参数是相反的.它是否违反了默认参数必须最后出现的规则?参数包不能具有默认值.

#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;
}
Run Code Online (Sandbox Code Playgroud)

这产生了

t.i = 1, t.str = huh??
Run Code Online (Sandbox Code Playgroud)

msc*_*msc 20

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

对于非模板函数,可以在稍后的同一范围内的函数声明中添加默认参数.不同范围内的声明具有完全不同的默认参数集.也就是说,内部作用域中的声明不从外部作用域中的声明中获取默认参数,反之亦然.在给定的函数声明中,具有默认参数的参数之后的每个参数都应具有在此声明或先前声明中提供的默认参数,或者应为函数参数包.默认参数不应由后来的声明(甚至不是相同的值)重新定义.[例如:

void g(int = 0, ...); // OK, ellipsis is not a parameter. So it can follow a parameter with a default argument
Run Code Online (Sandbox Code Playgroud)

  • (Nit挑选)这不回答问题(不是"它是",而是"*为什么*是允许的"). (3认同)
  • @KyleStrand你这样做,但我没有.相反,我认为最明智的解释是*为什么标准允许这样做?*还要注意问题不是标记语言律师.一般来说,最明智的答案是*为什么是这样且允许*不是*因为这就是法律是*.除非,也许你是律师. (3认同)

AzC*_*pey 10

作为rsp的优秀答案的补充,值得注意的是,这种行为具有逻辑意义.非默认的非参数包参数不能遵循默认参数,而不会导致必须指定默认参数 - 在这种情况下它不再是默认参数.

例如,如果允许以下内容:

void example(int x=0, int y);
Run Code Online (Sandbox Code Playgroud)

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

template <typename... T> void example(int x = 0, T&&... t);
Run Code Online (Sandbox Code Playgroud)

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

  • 更重要的是,`void example(int x = 0,int y);`*is*有时允许:如果先前的声明已经为`y`建立了默认值,则允许它.这与你的其他解释相符:这是可以使用'x`的默认值的一种方式. (2认同)

Gem*_*lor 8

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