Подтвердить что ты не робот

Почему пакет параметров разрешен после аргументов по умолчанию?

Возможно, мне не хватает чего-то очевидного, но следующие компилируются и запускаются, и я не уверен, почему. Я знаю этот, но в приведенном ниже примере позиция пакета параметров и аргумент по умолчанию отменены. Не нарушает ли это правило, что аргументы по умолчанию должны появляться последними? Пакет параметров не может иметь значения по умолчанию.

#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??
4b9b3361

Ответ 1

Из 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

Ответ 2

В дополнение к большому ответу rsp, также стоит отметить, что это поведение имеет логический смысл. Нестандартные аргументы без параметра-пакета не могут следовать аргументу по умолчанию, не приводя к тому, что в требовании необходимо указать аргумент по умолчанию - в этом случае он больше не является аргументом по умолчанию.

Например, если разрешено следующее:

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

Второй аргумент, отличный от значения по умолчанию, означает, что вызов функции должен быть структурирован example(1, 2);, поскольку первый параметр не может быть установлен по умолчанию. Это не касается пустого пакета параметров. Рассмотрим следующую функцию:

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

В этом случае по-прежнему возможно по умолчанию x, вызывая example();

Ответ 3

Почему это просто. Эффективно пакеты параметров всегда имеют значение по умолчанию: Пакеты параметров могут быть пустыми, поэтому это не будет противоречить понятию, что отсутствующие значения по умолчанию должны быть последними аргументами.