Простой тестовый пример:
#include <iostream>
struct v {};
int main() {
std::cout << __VERSION__ << '\n' << (new v < new v) << '\n';
}
Я знаю, что сравнение указателей имеет неуказанный результат, но это не имеет значения здесь (и аналогичный пример может быть получен с несколькими нажатиями клавиш, как в последующих фрагментах coliru).
Стандарт С++, который я могу вам сказать, в пункте 14.2 раздела:
После поиска имени находит, что имя является именем шаблона или что оператор-функция-идентификатор или идентификатор литерала-оператора относится к набору перегруженных функций, любой из которых является шаблоном функции, если это выполняется по <, < всегда берется как разделитель списка шаблонов-аргументов и никогда не работает как оператор меньшего размера.
Так как v
не является ни именем шаблона, ни идентификатором функции, я не понимаю, почему это должно применяться. И ни то, ни другое, по-видимому, clang:
4.2.1 Compatible Clang 3.8.0 (tags/RELEASE_380/final 263969)
1
Однако gcc (6.3.0) жалуется:
main.cpp: In function 'int main()':
main.cpp:4:46: error: 'v' is not a template
std::cout << __VERSION__ << '\n' << (new v < new v) << '\n';
^
Неужели я (и clang) что-то пропустил?
Версии без неопределенного поведения: clang gcc
Версия с минусом, а не меньше: gcc (нет ошибки компиляции)
Добавление
Gcc не имеет такой же проблемы с функциями; с функции шаблона он настаивает на том, что < должен быть разделителем аргументов шаблона, но не с функции без шаблона. Это добавляет вес аргументам, что это ошибка, поэтому я подал ее как Ошибка 79192.
Примечание:
В случае, если кому-то интересно, это произошло, когда я пытался ответить на этот вопрос, где вопросник писал грамматику для смутно языка С++ и наткнулся на вышеупомянутую двусмысленность. Я хотел объяснить решение, используемое С++, но несоответствие между двумя компиляторами затруднило работу.