Списки инициализаторов и RHS операторов

Я не понимаю, почему списки инициализатора нельзя использовать в RHS оператора. Рассматривать:

class foo { };

struct bar
{
    template<typename... T>
    bar(T const&...) { }
};

foo& operator<<(foo& f, bar const&) { return f; }

int main()
{
    foo baz;
    baz << {1, -2, "foo", 4, 5};

    return 0;
}

Последний Clang (также gcc) жалуется:

clang.cc:14:9: error: initializer list cannot be used on the right hand side of operator '<<'
    baz << {1, -2, "foo", 4, 5};
    ^  ~~~~~~~~~~~~~~~~~~~~

    ^  ~~~~~~~~~~~~~~~

Почему стандарт C++ запрещает это? Или по-другому, почему это не так, в отличие от

baz << bar{1, -2, "foo", 4, 5};

?

1 ответ

Решение

Действительно, окончательная версия C++11 не позволяет использовать списки инициализаторов в правой части (или, в этом отношении, слева) двоичного оператора.

Во-первых, списки инициализаторов не являются выражениями, как определено в §5 Стандарта. Аргументы функций, а также бинарных операторов, как правило, должны быть выражениями, и грамматика для выражений, определенных в §5, не включает синтаксис для скобок-init-списков (то есть чистых инициализаторов-списков; обратите внимание, что после имени типа следует с помощью фигурного списка инициализации, такого как bar {2,5,"hello",7} это выражение, хотя).

Для удобства использования чистых списков инициализаторов стандарт определяет различные исключения, которые обобщены в следующем (ненормативном) примечании:

§8.5.4 / 1 [...] Примечание: можно использовать инициализацию списка
- как инициализатор в определении переменной (8.5)
- как инициализатор в новом выражении (5.3.4)
- в отчете о возврате (6.6.3)
- в качестве аргумента функции (5.2.2)
- как нижний индекс (5.2.1)
- в качестве аргумента для вызова конструктора (8.5, 5.2.3)
- как инициализатор для нестатического члена данных (9.2)
- в mem-инициализаторе (12.6.2)
- в правой части задания (5.17)
[...]

Четвертый пункт выше явно разрешает чистые списки инициализаторов в качестве аргументов функции (вот почему operator<<(baz, {1, -2, "foo", 4, 5}); работает), пятый позволяет это в подстрочных выражениях (то есть в качестве аргумента operator[]например, mymap[{2,5,"hello"}] является законным), и последний элемент позволяет им в правой части присваивания (но не общие бинарные операторы).

Для бинарных операторов, таких как +, * или же <<следовательно, вы не можете поместить чистый список инициализатора (то есть тот, которому не предшествует имя типа) по обе стороны от них.

Что касается причин этого, проект / дискуссионный документ N2215, составленный Страуструпом и Дос Рейсом от 2007 года, дает глубокое понимание многих проблем со списками инициализаторов в различных контекстах. В частности, есть раздел о бинарных операторах (раздел 6.2):

Рассмотрим более общее использование списков инициализаторов. Например:

v = v+{3,4};
v = {6,7}+v;

Когда мы рассматриваем операторы как синтаксический сахар для функций, мы, естественно, считаем, что вышеуказанное эквивалентно

v = operator+(v,{3,4});
v = operator+({6,7},v);

Поэтому естественно распространить использование списков инициализаторов на выражения. Во многих случаях списки инициализаторов в сочетании с операторами являются "естественной" нотацией.
Однако нетривиально написать грамматику LR(1), которая позволяет произвольно использовать списки инициализаторов. Блок также начинается с {, поэтому разрешение списка инициализаторов, поскольку первый (крайний левый) объект выражения может привести к хаосу в грамматике.
Тривиально разрешить списки инициализаторов в качестве правого операнда бинарных операторов, в индексах и подобных изолированных частях грамматики. Настоящая проблема состоит в том, чтобы позволить ;a={1,2}+b; как оператор присваивания, не позволяя также ;{1,2}+b;, Мы подозреваем, что допускать списки инициализаторов в качестве правосторонних, но [sic] в качестве левых аргументов для большинства операторов - слишком много пустяков, [...]

Другими словами, списки инициализаторов не включены с правой стороны, потому что они не включены с левой стороны, и они не включены с левой стороны, потому что это было бы слишком большой проблемой для анализаторов.,

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

Другие вопросы по тегам