Позиция модификатора Declarator в вариативных шаблонах

Declarators. Да, деклараторы. Они являются источником множества дискуссий по кодированию. Это действительно хорошая тема для аргументов - С++ не определяет, какой из них лучше другого (это неважно!). И поэтому мы можем написать их, не беспокоясь о том, что кто-то может высмеять вас:

int x;

int& a = x;
int &b = x;

int* c = &x;
int *d = &x;

В синтаксических терминах b и d являются "более достоверными", чем остальные. Мы должны указать модификаторы декларатора перед именами:

int m, *n;   // m is an int; n is a pointer to int

Но поток, похоже, обратился в пользу одного. С помощью вариативных шаблонов С++ 11 положение деклараторов, по-видимому, ограничено формой, в которой модификаторы ближе к базовому типу:

template<typename... Ts>
void VariadicFuncRef(const Ts&... args) { }
                             ^
template<typename... Ts>
void VariadicFuncPtr(Ts*... args) { }
                       ^

Ошибка записи этих форм:

template<typename... Ts>
void VariadicFuncRef(const Ts... &args) { }

template<typename... Ts>
void VariadicFuncPtr(Ts... *args) { }

Для конкретного примера нажмите здесь.

Итак, мой вопрос таков: Почему мы ограничиваемся этой (юридической) формой и не можем использовать другую?

Любые мысли ребята?

ДОПОЛНИТЕЛЬНЫЙ 1: Меня также интересует дизайнерское решение о том, почему это "правило" "принудительно".

Ответ 1

Прежде всего, я бы не сказал, что int &a более допустим, чем int& a. Вы можете сказать, что это более читаемо или хорошая практика, но это совсем другое.

Во-вторых, синтаксис распаковки параметров T... можно читать как "расширяется тип-шаблон в левой части ..., образуя одинаковые или разные типы параметров фактической функции, соответствующие форме шаблона типа". Поэтому, когда вы пишете f(T&...), его можно развернуть до f(int&, float&, double&, Xyz&, Abc&). Но это не кажется настолько очевидным (по крайней мере для меня), когда синтаксис T...&. Так что, возможно, это одна из нескольких других возможных причин, почему стандарт сделал это так.

Также обратите внимание, что args в T&...args является необязательным. Поэтому, если вы его не пишете, то void f(T...&) выглядит странно (по крайней мере, для меня) и void f(T&...) выглядит эстетически по крайней мере.

Вы также можете сравнить синтаксисы, такие как: T * const & ... с T... * const &. Тип-образец более очевиден в предыдущем синтаксисе, чем в последнем.

Ответ 2

Старый синтаксис объявления был просто одним правилом с незначительным пробелом, но ваша идея - две. Я сомневаюсь, что комитет будет поддерживать два правила, если их будет достаточно.

Выбор размещения декларатора слева был, скорее всего, сделан по двум причинам:

  • idiomatic С++ в настоящее время предпочитает int* x, а не int *x (например, Bjarne использует первый). Большинство считают синтаксис декларатора ошибкой.
  • Расширение пакета параметров расширяет элементы слева от ..., а не направо.

Ответ 3

Совершенство достигается, когда нечего добавить, но когда ничего не осталось, чтобы отнять.

- Антуан де Сент-Экзюпери

Трудность программирования языка программирования заключается не в добавлении функций, а в воздержании от их добавления. Каждая функция, каждая вариация синтаксиса, имеет стоимость:

  • они должны быть специально закодированы в компиляторе
  • они создают риск появления ошибок
  • они создают риск плохо взаимодействовать с другим признаком/изменением
  • ...

Синтаксис в C и С++ является (в основном) пробелом без учета чувствительности, поэтому не имеет значения, где вы размещаете & или *, и обе предпочтения могут сосуществовать без дополнительной нагрузки; однако в случае вариационных шаблонов это имеет значение из-за токена .... Таким образом, комитет решил выбрать один, и они выбрали самый идиоматический в С++ (который делал упор на полный тип, а не на базовый тип).