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

时间:2017-11-16 13:14:53

标签: c++ c++11 c++14 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??

3 个答案:

答案 0 :(得分:20)

From 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

答案 1 :(得分:10)

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

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

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

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

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

在这种情况下,仍然可以通过调用x

来默认example();

答案 2 :(得分:8)

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