#c #bnf
#c #bnf
Вопрос:
У меня есть такой код, скомпилируйте с помощью «g -Wall -g -std= c 11 test.cpp «, который не компилируется, потому что ошибка: ожидаемое первичное выражение перед токеном ‘)’
#include <functional>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec;
for(int i=0;i<10; i)
{
vec.push_back(i);
}
std::sort(vec.begin(),vec.end(),std::less<int>); //should be std::less<int>()
}
Но стандарт гласит:
primary-expression:
literal
this
( expression )
id-expression
lambda-expression
id-expression:
unqualified-id
qualified-id
unqualified-id:
identifier
operator-function-id
conversion-function-id
literal-operator-id
~ class-name
~ decltype-specifier
template-id
template-id
simple-template-id
simple-template-id
template-name <template-argument-list>
Итак, кажется, что std::less — это идентификатор шаблона, поэтому это первичное выражение.
Комментарии:
1. какой компилятор вы используете?
2. FWIW, Clang: ошибка: ожидается ‘(‘ для приведения в стиле функции или построения типа
3. @MantoshKumar, вероятно, GCC. 4.9 выдает ошибку.
4. Похоже, что проблема в сообщении об ошибке компиляции Clang. Я запустил ту же программу в VS2010 и получил следующую «ошибку C2275: ‘std::less<_Ty>’: незаконное использование этого типа в качестве выражения».
5. @MantoshKumar, в ошибке Clang нет ничего плохого. По сути, это говорит о том, что «у вас есть половина выражения этого типа, но вам не хватает другой половины».
Ответ №1:
Грамматическая корректность не обязательно делает программу семантически корректной. Создание грамматики из primary-expression -> template-id позволяет использовать специализацию шаблона функции в качестве выражения, например, это допустимо:
template <typename T>
bool less(const Tamp; a, const Tamp; b) { return a < b; }
int main() {
std::vector<int> vec;
std::sort(vec.begin(), vec.end(), less<int>);
}
Однако идентификатор шаблона, который ссылается на шаблон класса, не может использоваться в качестве выражения.
Комментарии:
1. 1. Разница между семантикой и синтаксисом и в лучшие времена незаметна, а в C тем более. Стандарт не делает различий между различными типами плохо сформированных программ: он просто определяет хорошо сформированную программу как «программу на C , построенную в соответствии с правилами синтаксиса, диагностируемыми семантическими правилами и правилом единого определения», а плохо сформированную программу как программу, которая не является правильно сформированной.
2. @Casey. Я почти согласен с вами. Я думаю, что программа семантически неверна, но она является основным выражением, значит ли это, что g сообщает об ошибке неправильного типа? Кажется, что код ошибки clang «незаконное использование этого типа в качестве выражения» более разумный.
Ответ №2:
В этом разница между синтаксическим анализатором и семантическим анализатором. Грамматика C сообщает вам только то, что является грамматическим — то, что будет проходить через анализатор. Например, грамматика также позволит вам сделать что-то вроде:
std::sort(vec.begin(), vec.end(), ~MyClass);
по той же причине — потому ~ class-name
что это unqualified-id
. Вам нужно посмотреть на семантические правила языка, чтобы определить, правильно ли сформирована программа, а не просто смотреть на грамматику, и семантические правила языка требуют здесь значения, а не типа.
В частности, я полагаю, что стандарт говорит об этом через правила для оператора вызова функции ( ()
) в C 11 5.2.2 [expr.call] / 4: (выделение мое)
При вызове функции каждый параметр (8.3.5) должен быть инициализирован (8.5, 12.8, 12.1) соответствующим аргументом.
8.5 [dcl.init]/1: (курсив мой)
Декларатор может указать начальное значение для объявляемого идентификатора. Идентификатор обозначает инициализируемую переменную.
Но я не специалист по стандартам, и я не в комитете, так что YMMV.
Ответ №3:
Честно говоря, я не думал об этом с точки зрения выражений. Но то, как я думаю об этом — std::sort
хочет объект для его третьего параметра. std::less<int>
это просто объявление типа. std::less<int>()
создает объект, который std::sort
требуется.