Почему идентификатор шаблона в "A <0>= 0" не компилируется без пробела из-за оператора "больше или равно" "> ="?

template <int>
using A = int;

void f(A<0>=0);   // Attempting to declare a function f taking int,
                  // with the default argument 0

// Works as expected:
// void f(A<0> = 0);

Это не компилируется на GCC 4.9.2 или Clang 3.5 - не говоря уже о ICC или VС++. По-видимому, бит >= анализируется как оператор большего или равного. Однако это, по-видимому, неверно в отношении [temp.names]/3:

После поиска имени (3.4) обнаружено, что имя является именем шаблона или идентификатор-оператор-идентификатор или идентификатор-буква - оператор-идентификатор относится к набору перегруженных функций, любой из которых является шаблоном функции, если за этим следует <, < всегда принимается за разделитель список шаблонов-аргументов и никогда не меньше, чем оператор. При анализе списка шаблонов-аргументов первый не-вложенный > 138 принимается за конечный разделитель, а не больше оператора. [..] [Пример:

template<int i> class X { /* ...*/ };

X< 1>2 > x1; // syntax error
X<(1>2)> x2; // OK

- конец примера]

138) A >, который включает идентификатор типа a dynamic_cast, static_cast, reinterpret_cast или const_cast, или который охватывает template-arguments следующего идентификатора шаблона, считается вложенным для целей этого описания.

Я что-то упустил или это ошибка компилятора?

Ответ 1

Этот эффект максимальный принцип клана, в котором лексический анализатор принимает как можно больше символов, чтобы сформировать действительный токен. Это описано в черновом стандартном разделе С++ 2.5 [lex.pptoken], в котором говорится:

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

В любых случаях, например, приведенных выше, требуется определенное исключение, например, для этого случая для <::, мы можем увидеть пример в следующем коде:

template<typename T> class SomeClass;
class Class;

SomeClass<::Class>* cls;

который рассматривается в этом вопросе, исключение указано в марке чуть выше максимального правила munch:

В противном случае, если следующие три символа: <:: и последующий символ не равен: nor > , < рассматривается как токен препроцессора сам по себе, а не как первый символ альтернативного токена <:.

и, конечно, не вложенные >, которые вы цитируете в своем вопросе.

Заметьте, что >= - токен препроцессора из раздела 2.13 [lex.operators], который гласит:

Лексическое представление программ на С++ включает в себя ряд токенов предварительной обработки, которые используются в синтаксис препроцессора или преобразуются в токены для операторов и пунктуаторов:

и включает >= в список.

> fix

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

С момента появления угловых скобок программисты на C++ был удивлен тем, что два последовательных прямоугольных скобки должны быть разделены пробелами:

#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // Error

Проблема заключается в <сильном > немедленном следствии "максимального munch" принцип и тот факт, что → - действительный токен (правый сдвиг) в С++.

Этот вопрос является второстепенным, но сохраняющим, раздражающим и несколько смущающая проблема. Если стоимость разумна, кажется, стоит устранить неожиданность.

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

Также указывает случай >=:

Также стоит отметить, что проблема может также возникать при → = и >= токены. Например

void func(List<B>= default_val1);
void func(List<List<B>>= default_val2);

Обе эти формы в настоящее время плохо сформированы. Может быть желательно, чтобы также рассмотрите этот вопрос, но этот документ не предлагает этого.

Обратите внимание, что это изменение отменило обратную совместимость с С++ 03.